From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
patches@lists.linux.dev, Joel Fernandes <joelagnelf@nvidia.com>,
Dave Airlie <airlied@redhat.com>, Sasha Levin <sashal@kernel.org>
Subject: [PATCH 6.12 510/602] gpu: Move DRM buddy allocator one level up (part two)
Date: Thu, 30 Jul 2026 16:15:02 +0200 [thread overview]
Message-ID: <20260730141446.712461318@linuxfoundation.org> (raw)
In-Reply-To: <20260730141435.976815864@linuxfoundation.org>
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joel Fernandes <joelagnelf@nvidia.com>
[ Upstream commit ba110db8e1bc206c13fd7d985e79b033f53bfdea ]
Move the DRM buddy allocator one level up so that it can be used by GPU
drivers (example, nova-core) that have usecases other than DRM (such as
VFIO vGPU support). Modify the API, structures and Kconfigs to use
"gpu_buddy" terminology. Adapt the drivers and tests to use the new API.
The commit cannot be split due to bisectability, however no functional
change is intended. Verified by running K-UNIT tests and build tested
various configurations.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
Reviewed-by: Dave Airlie <airlied@redhat.com>
[airlied: I've split this into two so git can find copies easier.
I've also just nuked drm_random library, that stuff needs to be done
elsewhere and only the buddy tests seem to be using it].
Signed-off-by: Dave Airlie <airlied@redhat.com>
Stable-dep-of: 56bc6384314f ("gpu/buddy: bail out of try_harder when alignment cannot be honoured")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
Documentation/gpu/drm-mm.rst | 10
drivers/gpu/Kconfig | 13
drivers/gpu/Makefile | 3
drivers/gpu/buddy.c | 1322 +++++++++++++++++++
drivers/gpu/drm/Kconfig | 6
drivers/gpu/drm/Makefile | 1
drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h | 12
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 77 -
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 18
drivers/gpu/drm/drm_buddy.c | 1279 ------------------
drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 2
drivers/gpu/drm/i915/i915_scatterlist.c | 10
drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 55
drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 4
drivers/gpu/drm/i915/selftests/intel_memory_region.c | 20
drivers/gpu/drm/lib/drm_random.c | 43
drivers/gpu/drm/lib/drm_random.h | 28
drivers/gpu/drm/tests/Makefile | 1
drivers/gpu/drm/tests/drm_buddy_test.c | 778 -----------
drivers/gpu/drm/tests/drm_exec_test.c | 2
drivers/gpu/drm/tests/drm_mm_test.c | 2
drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c | 4
drivers/gpu/drm/ttm/tests/ttm_mock_manager.c | 18
drivers/gpu/drm/ttm/tests/ttm_mock_manager.h | 4
drivers/gpu/drm/xe/xe_res_cursor.h | 34
drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 73 -
drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h | 4
drivers/gpu/tests/Makefile | 4
drivers/gpu/tests/gpu_buddy_test.c | 778 +++++++++++
drivers/gpu/tests/gpu_random.c | 43
drivers/gpu/tests/gpu_random.h | 28
drivers/video/Kconfig | 1
include/drm/drm_buddy.h | 174 --
include/linux/gpu_buddy.h | 188 ++
34 files changed, 2576 insertions(+), 2463 deletions(-)
create mode 100644 drivers/gpu/Kconfig
create mode 100644 drivers/gpu/buddy.c
create mode 100644 drivers/gpu/tests/Makefile
rename drivers/gpu/{drm/tests/drm_buddy_test.c => tests/gpu_buddy_test.c} (70%)
rename drivers/gpu/{drm/lib/drm_random.c => tests/gpu_random.c} (58%)
rename drivers/gpu/{drm/lib/drm_random.h => tests/gpu_random.h} (53%)
create mode 100644 include/linux/gpu_buddy.h
--- a/Documentation/gpu/drm-mm.rst
+++ b/Documentation/gpu/drm-mm.rst
@@ -509,8 +509,14 @@ DRM GPUVM Function References
DRM Buddy Allocator
===================
-DRM Buddy Function References
------------------------------
+Buddy Allocator Function References (GPU buddy)
+-----------------------------------------------
+
+.. kernel-doc:: drivers/gpu/buddy.c
+ :export:
+
+DRM Buddy Specific Logging Function References
+----------------------------------------------
.. kernel-doc:: drivers/gpu/drm/drm_buddy.c
:export:
--- /dev/null
+++ b/drivers/gpu/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config GPU_BUDDY
+ bool
+ help
+ A page based buddy allocator for GPU memory.
+
+config GPU_BUDDY_KUNIT_TEST
+ tristate "KUnit tests for GPU buddy allocator" if !KUNIT_ALL_TESTS
+ depends on GPU_BUDDY && KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ KUnit tests for the GPU buddy allocator.
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -2,6 +2,7 @@
# drm/tegra depends on host1x, so if both drivers are built-in care must be
# taken to initialize them in the correct order. Link order is the only way
# to ensure this currently.
-obj-y += host1x/ drm/ vga/
+obj-y += host1x/ drm/ vga/ tests/
obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
obj-$(CONFIG_TRACE_GPU_MEM) += trace/
+obj-$(CONFIG_GPU_BUDDY) += buddy.o
--- /dev/null
+++ b/drivers/gpu/buddy.c
@@ -0,0 +1,1322 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#include <kunit/test-bug.h>
+
+#include <linux/export.h>
+#include <linux/kmemleak.h>
+#include <linux/module.h>
+#include <linux/sizes.h>
+
+#include <linux/gpu_buddy.h>
+
+static struct kmem_cache *slab_blocks;
+
+static struct gpu_buddy_block *gpu_block_alloc(struct gpu_buddy *mm,
+ struct gpu_buddy_block *parent,
+ unsigned int order,
+ u64 offset)
+{
+ struct gpu_buddy_block *block;
+
+ BUG_ON(order > GPU_BUDDY_MAX_ORDER);
+
+ block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL);
+ if (!block)
+ return NULL;
+
+ block->header = offset;
+ block->header |= order;
+ block->parent = parent;
+
+ RB_CLEAR_NODE(&block->rb);
+
+ BUG_ON(block->header & GPU_BUDDY_HEADER_UNUSED);
+ return block;
+}
+
+static void gpu_block_free(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ kmem_cache_free(slab_blocks, block);
+}
+
+static enum gpu_buddy_free_tree
+get_block_tree(struct gpu_buddy_block *block)
+{
+ return gpu_buddy_block_is_clear(block) ?
+ GPU_BUDDY_CLEAR_TREE : GPU_BUDDY_DIRTY_TREE;
+}
+
+static struct gpu_buddy_block *
+rbtree_get_free_block(const struct rb_node *node)
+{
+ return node ? rb_entry(node, struct gpu_buddy_block, rb) : NULL;
+}
+
+static struct gpu_buddy_block *
+rbtree_last_free_block(struct rb_root *root)
+{
+ return rbtree_get_free_block(rb_last(root));
+}
+
+static bool rbtree_is_empty(struct rb_root *root)
+{
+ return RB_EMPTY_ROOT(root);
+}
+
+static bool gpu_buddy_block_offset_less(const struct gpu_buddy_block *block,
+ const struct gpu_buddy_block *node)
+{
+ return gpu_buddy_block_offset(block) < gpu_buddy_block_offset(node);
+}
+
+static bool rbtree_block_offset_less(struct rb_node *block,
+ const struct rb_node *node)
+{
+ return gpu_buddy_block_offset_less(rbtree_get_free_block(block),
+ rbtree_get_free_block(node));
+}
+
+static void rbtree_insert(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block,
+ enum gpu_buddy_free_tree tree)
+{
+ rb_add(&block->rb,
+ &mm->free_trees[tree][gpu_buddy_block_order(block)],
+ rbtree_block_offset_less);
+}
+
+static void rbtree_remove(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ unsigned int order = gpu_buddy_block_order(block);
+ enum gpu_buddy_free_tree tree;
+ struct rb_root *root;
+
+ tree = get_block_tree(block);
+ root = &mm->free_trees[tree][order];
+
+ rb_erase(&block->rb, root);
+ RB_CLEAR_NODE(&block->rb);
+}
+
+static void clear_reset(struct gpu_buddy_block *block)
+{
+ block->header &= ~GPU_BUDDY_HEADER_CLEAR;
+}
+
+static void mark_cleared(struct gpu_buddy_block *block)
+{
+ block->header |= GPU_BUDDY_HEADER_CLEAR;
+}
+
+static void mark_allocated(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ block->header &= ~GPU_BUDDY_HEADER_STATE;
+ block->header |= GPU_BUDDY_ALLOCATED;
+
+ rbtree_remove(mm, block);
+}
+
+static void mark_free(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ enum gpu_buddy_free_tree tree;
+
+ block->header &= ~GPU_BUDDY_HEADER_STATE;
+ block->header |= GPU_BUDDY_FREE;
+
+ tree = get_block_tree(block);
+ rbtree_insert(mm, block, tree);
+}
+
+static void mark_split(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ block->header &= ~GPU_BUDDY_HEADER_STATE;
+ block->header |= GPU_BUDDY_SPLIT;
+
+ rbtree_remove(mm, block);
+}
+
+static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
+{
+ return s1 <= e2 && e1 >= s2;
+}
+
+static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2)
+{
+ return s1 <= s2 && e1 >= e2;
+}
+
+static struct gpu_buddy_block *
+__get_buddy(struct gpu_buddy_block *block)
+{
+ struct gpu_buddy_block *parent;
+
+ parent = block->parent;
+ if (!parent)
+ return NULL;
+
+ if (parent->left == block)
+ return parent->right;
+
+ return parent->left;
+}
+
+static unsigned int __gpu_buddy_free(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block,
+ bool force_merge)
+{
+ struct gpu_buddy_block *parent;
+ unsigned int order;
+
+ while ((parent = block->parent)) {
+ struct gpu_buddy_block *buddy;
+
+ buddy = __get_buddy(block);
+
+ if (!gpu_buddy_block_is_free(buddy))
+ break;
+
+ if (!force_merge) {
+ /*
+ * Check the block and its buddy clear state and exit
+ * the loop if they both have the dissimilar state.
+ */
+ if (gpu_buddy_block_is_clear(block) !=
+ gpu_buddy_block_is_clear(buddy))
+ break;
+
+ if (gpu_buddy_block_is_clear(block))
+ mark_cleared(parent);
+ }
+
+ rbtree_remove(mm, buddy);
+ if (force_merge && gpu_buddy_block_is_clear(buddy))
+ mm->clear_avail -= gpu_buddy_block_size(mm, buddy);
+
+ gpu_block_free(mm, block);
+ gpu_block_free(mm, buddy);
+
+ block = parent;
+ }
+
+ order = gpu_buddy_block_order(block);
+ mark_free(mm, block);
+
+ return order;
+}
+
+static int __force_merge(struct gpu_buddy *mm,
+ u64 start,
+ u64 end,
+ unsigned int min_order)
+{
+ unsigned int tree, order;
+ int i;
+
+ if (!min_order)
+ return -ENOMEM;
+
+ if (min_order > mm->max_order)
+ return -EINVAL;
+
+ for_each_free_tree(tree) {
+ for (i = min_order - 1; i >= 0; i--) {
+ struct rb_node *iter = rb_last(&mm->free_trees[tree][i]);
+
+ while (iter) {
+ struct gpu_buddy_block *block, *buddy;
+ u64 block_start, block_end;
+
+ block = rbtree_get_free_block(iter);
+ iter = rb_prev(iter);
+
+ if (!block || !block->parent)
+ continue;
+
+ block_start = gpu_buddy_block_offset(block);
+ block_end = block_start + gpu_buddy_block_size(mm, block) - 1;
+
+ if (!contains(start, end, block_start, block_end))
+ continue;
+
+ buddy = __get_buddy(block);
+ if (!gpu_buddy_block_is_free(buddy))
+ continue;
+
+ WARN_ON(gpu_buddy_block_is_clear(block) ==
+ gpu_buddy_block_is_clear(buddy));
+
+ /*
+ * Advance to the next node when the current node is the buddy,
+ * as freeing the block will also remove its buddy from the tree.
+ */
+ if (iter == &buddy->rb)
+ iter = rb_prev(iter);
+
+ rbtree_remove(mm, block);
+ if (gpu_buddy_block_is_clear(block))
+ mm->clear_avail -= gpu_buddy_block_size(mm, block);
+
+ order = __gpu_buddy_free(mm, block, true);
+ if (order >= min_order)
+ return 0;
+ }
+ }
+ }
+
+ return -ENOMEM;
+}
+
+/**
+ * gpu_buddy_init - init memory manager
+ *
+ * @mm: GPU buddy manager to initialize
+ * @size: size in bytes to manage
+ * @chunk_size: minimum page size in bytes for our allocations
+ *
+ * Initializes the memory manager and its resources.
+ *
+ * Returns:
+ * 0 on success, error code on failure.
+ */
+int gpu_buddy_init(struct gpu_buddy *mm, u64 size, u64 chunk_size)
+{
+ unsigned int i, j, root_count = 0;
+ u64 offset = 0;
+
+ if (size < chunk_size)
+ return -EINVAL;
+
+ if (chunk_size < SZ_4K)
+ return -EINVAL;
+
+ if (!is_power_of_2(chunk_size))
+ return -EINVAL;
+
+ size = round_down(size, chunk_size);
+
+ mm->size = size;
+ mm->avail = size;
+ mm->clear_avail = 0;
+ mm->chunk_size = chunk_size;
+ mm->max_order = ilog2(size) - ilog2(chunk_size);
+
+ BUG_ON(mm->max_order > GPU_BUDDY_MAX_ORDER);
+
+ mm->free_trees = kmalloc_array(GPU_BUDDY_MAX_FREE_TREES,
+ sizeof(*mm->free_trees),
+ GFP_KERNEL);
+ if (!mm->free_trees)
+ return -ENOMEM;
+
+ for_each_free_tree(i) {
+ mm->free_trees[i] = kmalloc_array(mm->max_order + 1,
+ sizeof(struct rb_root),
+ GFP_KERNEL);
+ if (!mm->free_trees[i])
+ goto out_free_tree;
+
+ for (j = 0; j <= mm->max_order; ++j)
+ mm->free_trees[i][j] = RB_ROOT;
+ }
+
+ mm->n_roots = hweight64(size);
+
+ mm->roots = kmalloc_array(mm->n_roots,
+ sizeof(struct gpu_buddy_block *),
+ GFP_KERNEL);
+ if (!mm->roots)
+ goto out_free_tree;
+
+ /*
+ * Split into power-of-two blocks, in case we are given a size that is
+ * not itself a power-of-two.
+ */
+ do {
+ struct gpu_buddy_block *root;
+ unsigned int order;
+ u64 root_size;
+
+ order = ilog2(size) - ilog2(chunk_size);
+ root_size = chunk_size << order;
+
+ root = gpu_block_alloc(mm, NULL, order, offset);
+ if (!root)
+ goto out_free_roots;
+
+ mark_free(mm, root);
+
+ BUG_ON(root_count > mm->max_order);
+ BUG_ON(gpu_buddy_block_size(mm, root) < chunk_size);
+
+ mm->roots[root_count] = root;
+
+ offset += root_size;
+ size -= root_size;
+ root_count++;
+ } while (size);
+
+ return 0;
+
+out_free_roots:
+ while (root_count--)
+ gpu_block_free(mm, mm->roots[root_count]);
+ kfree(mm->roots);
+out_free_tree:
+ while (i--)
+ kfree(mm->free_trees[i]);
+ kfree(mm->free_trees);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL(gpu_buddy_init);
+
+/**
+ * gpu_buddy_fini - tear down the memory manager
+ *
+ * @mm: GPU buddy manager to free
+ *
+ * Cleanup memory manager resources and the freetree
+ */
+void gpu_buddy_fini(struct gpu_buddy *mm)
+{
+ u64 root_size, size, start;
+ unsigned int order;
+ int i;
+
+ size = mm->size;
+
+ for (i = 0; i < mm->n_roots; ++i) {
+ order = ilog2(size) - ilog2(mm->chunk_size);
+ start = gpu_buddy_block_offset(mm->roots[i]);
+ __force_merge(mm, start, start + size, order);
+
+ if (WARN_ON(!gpu_buddy_block_is_free(mm->roots[i])))
+ kunit_fail_current_test("buddy_fini() root");
+
+ gpu_block_free(mm, mm->roots[i]);
+
+ root_size = mm->chunk_size << order;
+ size -= root_size;
+ }
+
+ WARN_ON(mm->avail != mm->size);
+
+ for_each_free_tree(i)
+ kfree(mm->free_trees[i]);
+ kfree(mm->free_trees);
+ kfree(mm->roots);
+}
+EXPORT_SYMBOL(gpu_buddy_fini);
+
+static int split_block(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ unsigned int block_order = gpu_buddy_block_order(block) - 1;
+ u64 offset = gpu_buddy_block_offset(block);
+
+ BUG_ON(!gpu_buddy_block_is_free(block));
+ BUG_ON(!gpu_buddy_block_order(block));
+
+ block->left = gpu_block_alloc(mm, block, block_order, offset);
+ if (!block->left)
+ return -ENOMEM;
+
+ block->right = gpu_block_alloc(mm, block, block_order,
+ offset + (mm->chunk_size << block_order));
+ if (!block->right) {
+ gpu_block_free(mm, block->left);
+ return -ENOMEM;
+ }
+
+ mark_split(mm, block);
+
+ if (gpu_buddy_block_is_clear(block)) {
+ mark_cleared(block->left);
+ mark_cleared(block->right);
+ clear_reset(block);
+ }
+
+ mark_free(mm, block->left);
+ mark_free(mm, block->right);
+
+ return 0;
+}
+
+/**
+ * gpu_get_buddy - get buddy address
+ *
+ * @block: GPU buddy block
+ *
+ * Returns the corresponding buddy block for @block, or NULL
+ * if this is a root block and can't be merged further.
+ * Requires some kind of locking to protect against
+ * any concurrent allocate and free operations.
+ */
+struct gpu_buddy_block *
+gpu_get_buddy(struct gpu_buddy_block *block)
+{
+ return __get_buddy(block);
+}
+EXPORT_SYMBOL(gpu_get_buddy);
+
+/**
+ * gpu_buddy_reset_clear - reset blocks clear state
+ *
+ * @mm: GPU buddy manager
+ * @is_clear: blocks clear state
+ *
+ * Reset the clear state based on @is_clear value for each block
+ * in the freetree.
+ */
+void gpu_buddy_reset_clear(struct gpu_buddy *mm, bool is_clear)
+{
+ enum gpu_buddy_free_tree src_tree, dst_tree;
+ u64 root_size, size, start;
+ unsigned int order;
+ int i;
+
+ size = mm->size;
+ for (i = 0; i < mm->n_roots; ++i) {
+ order = ilog2(size) - ilog2(mm->chunk_size);
+ start = gpu_buddy_block_offset(mm->roots[i]);
+ __force_merge(mm, start, start + size, order);
+
+ root_size = mm->chunk_size << order;
+ size -= root_size;
+ }
+
+ src_tree = is_clear ? GPU_BUDDY_DIRTY_TREE : GPU_BUDDY_CLEAR_TREE;
+ dst_tree = is_clear ? GPU_BUDDY_CLEAR_TREE : GPU_BUDDY_DIRTY_TREE;
+
+ for (i = 0; i <= mm->max_order; ++i) {
+ struct rb_root *root = &mm->free_trees[src_tree][i];
+ struct gpu_buddy_block *block, *tmp;
+
+ rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) {
+ rbtree_remove(mm, block);
+ if (is_clear) {
+ mark_cleared(block);
+ mm->clear_avail += gpu_buddy_block_size(mm, block);
+ } else {
+ clear_reset(block);
+ mm->clear_avail -= gpu_buddy_block_size(mm, block);
+ }
+
+ rbtree_insert(mm, block, dst_tree);
+ }
+ }
+}
+EXPORT_SYMBOL(gpu_buddy_reset_clear);
+
+/**
+ * gpu_buddy_free_block - free a block
+ *
+ * @mm: GPU buddy manager
+ * @block: block to be freed
+ */
+void gpu_buddy_free_block(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ BUG_ON(!gpu_buddy_block_is_allocated(block));
+ mm->avail += gpu_buddy_block_size(mm, block);
+ if (gpu_buddy_block_is_clear(block))
+ mm->clear_avail += gpu_buddy_block_size(mm, block);
+
+ __gpu_buddy_free(mm, block, false);
+}
+EXPORT_SYMBOL(gpu_buddy_free_block);
+
+static void __gpu_buddy_free_list(struct gpu_buddy *mm,
+ struct list_head *objects,
+ bool mark_clear,
+ bool mark_dirty)
+{
+ struct gpu_buddy_block *block, *on;
+
+ WARN_ON(mark_dirty && mark_clear);
+
+ list_for_each_entry_safe(block, on, objects, link) {
+ if (mark_clear)
+ mark_cleared(block);
+ else if (mark_dirty)
+ clear_reset(block);
+ gpu_buddy_free_block(mm, block);
+ cond_resched();
+ }
+ INIT_LIST_HEAD(objects);
+}
+
+static void gpu_buddy_free_list_internal(struct gpu_buddy *mm,
+ struct list_head *objects)
+{
+ /*
+ * Don't touch the clear/dirty bit, since allocation is still internal
+ * at this point. For example we might have just failed part of the
+ * allocation.
+ */
+ __gpu_buddy_free_list(mm, objects, false, false);
+}
+
+/**
+ * gpu_buddy_free_list - free blocks
+ *
+ * @mm: GPU buddy manager
+ * @objects: input list head to free blocks
+ * @flags: optional flags like GPU_BUDDY_CLEARED
+ */
+void gpu_buddy_free_list(struct gpu_buddy *mm,
+ struct list_head *objects,
+ unsigned int flags)
+{
+ bool mark_clear = flags & GPU_BUDDY_CLEARED;
+
+ __gpu_buddy_free_list(mm, objects, mark_clear, !mark_clear);
+}
+EXPORT_SYMBOL(gpu_buddy_free_list);
+
+static bool block_incompatible(struct gpu_buddy_block *block, unsigned int flags)
+{
+ bool needs_clear = flags & GPU_BUDDY_CLEAR_ALLOCATION;
+
+ return needs_clear != gpu_buddy_block_is_clear(block);
+}
+
+static struct gpu_buddy_block *
+__alloc_range_bias(struct gpu_buddy *mm,
+ u64 start, u64 end,
+ unsigned int order,
+ unsigned long flags,
+ bool fallback)
+{
+ u64 req_size = mm->chunk_size << order;
+ struct gpu_buddy_block *block;
+ struct gpu_buddy_block *buddy;
+ LIST_HEAD(dfs);
+ int err;
+ int i;
+
+ end = end - 1;
+
+ for (i = 0; i < mm->n_roots; ++i)
+ list_add_tail(&mm->roots[i]->tmp_link, &dfs);
+
+ do {
+ u64 block_start;
+ u64 block_end;
+
+ block = list_first_entry_or_null(&dfs,
+ struct gpu_buddy_block,
+ tmp_link);
+ if (!block)
+ break;
+
+ list_del(&block->tmp_link);
+
+ if (gpu_buddy_block_order(block) < order)
+ continue;
+
+ block_start = gpu_buddy_block_offset(block);
+ block_end = block_start + gpu_buddy_block_size(mm, block) - 1;
+
+ if (!overlaps(start, end, block_start, block_end))
+ continue;
+
+ if (gpu_buddy_block_is_allocated(block))
+ continue;
+
+ if (block_start < start || block_end > end) {
+ u64 adjusted_start = max(block_start, start);
+ u64 adjusted_end = min(block_end, end);
+
+ if (round_down(adjusted_end + 1, req_size) <=
+ round_up(adjusted_start, req_size))
+ continue;
+ }
+
+ if (!fallback && block_incompatible(block, flags))
+ continue;
+
+ if (contains(start, end, block_start, block_end) &&
+ order == gpu_buddy_block_order(block)) {
+ /*
+ * Find the free block within the range.
+ */
+ if (gpu_buddy_block_is_free(block))
+ return block;
+
+ continue;
+ }
+
+ if (!gpu_buddy_block_is_split(block)) {
+ err = split_block(mm, block);
+ if (unlikely(err))
+ goto err_undo;
+ }
+
+ list_add(&block->right->tmp_link, &dfs);
+ list_add(&block->left->tmp_link, &dfs);
+ } while (1);
+
+ return ERR_PTR(-ENOSPC);
+
+err_undo:
+ /*
+ * We really don't want to leave around a bunch of split blocks, since
+ * bigger is better, so make sure we merge everything back before we
+ * free the allocated blocks.
+ */
+ buddy = __get_buddy(block);
+ if (buddy &&
+ (gpu_buddy_block_is_free(block) &&
+ gpu_buddy_block_is_free(buddy)))
+ __gpu_buddy_free(mm, block, false);
+ return ERR_PTR(err);
+}
+
+static struct gpu_buddy_block *
+__gpu_buddy_alloc_range_bias(struct gpu_buddy *mm,
+ u64 start, u64 end,
+ unsigned int order,
+ unsigned long flags)
+{
+ struct gpu_buddy_block *block;
+ bool fallback = false;
+
+ block = __alloc_range_bias(mm, start, end, order,
+ flags, fallback);
+ if (IS_ERR(block))
+ return __alloc_range_bias(mm, start, end, order,
+ flags, !fallback);
+
+ return block;
+}
+
+static struct gpu_buddy_block *
+get_maxblock(struct gpu_buddy *mm,
+ unsigned int order,
+ enum gpu_buddy_free_tree tree)
+{
+ struct gpu_buddy_block *max_block = NULL, *block = NULL;
+ struct rb_root *root;
+ unsigned int i;
+
+ for (i = order; i <= mm->max_order; ++i) {
+ root = &mm->free_trees[tree][i];
+ block = rbtree_last_free_block(root);
+ if (!block)
+ continue;
+
+ if (!max_block) {
+ max_block = block;
+ continue;
+ }
+
+ if (gpu_buddy_block_offset(block) >
+ gpu_buddy_block_offset(max_block)) {
+ max_block = block;
+ }
+ }
+
+ return max_block;
+}
+
+static struct gpu_buddy_block *
+alloc_from_freetree(struct gpu_buddy *mm,
+ unsigned int order,
+ unsigned long flags)
+{
+ struct gpu_buddy_block *block = NULL;
+ struct rb_root *root;
+ enum gpu_buddy_free_tree tree;
+ unsigned int tmp;
+ int err;
+
+ tree = (flags & GPU_BUDDY_CLEAR_ALLOCATION) ?
+ GPU_BUDDY_CLEAR_TREE : GPU_BUDDY_DIRTY_TREE;
+
+ if (flags & GPU_BUDDY_TOPDOWN_ALLOCATION) {
+ block = get_maxblock(mm, order, tree);
+ if (block)
+ /* Store the obtained block order */
+ tmp = gpu_buddy_block_order(block);
+ } else {
+ for (tmp = order; tmp <= mm->max_order; ++tmp) {
+ /* Get RB tree root for this order and tree */
+ root = &mm->free_trees[tree][tmp];
+ block = rbtree_last_free_block(root);
+ if (block)
+ break;
+ }
+ }
+
+ if (!block) {
+ /* Try allocating from the other tree */
+ tree = (tree == GPU_BUDDY_CLEAR_TREE) ?
+ GPU_BUDDY_DIRTY_TREE : GPU_BUDDY_CLEAR_TREE;
+
+ for (tmp = order; tmp <= mm->max_order; ++tmp) {
+ root = &mm->free_trees[tree][tmp];
+ block = rbtree_last_free_block(root);
+ if (block)
+ break;
+ }
+
+ if (!block)
+ return ERR_PTR(-ENOSPC);
+ }
+
+ BUG_ON(!gpu_buddy_block_is_free(block));
+
+ while (tmp != order) {
+ err = split_block(mm, block);
+ if (unlikely(err))
+ goto err_undo;
+
+ block = block->right;
+ tmp--;
+ }
+ return block;
+
+err_undo:
+ if (tmp != order)
+ __gpu_buddy_free(mm, block, false);
+ return ERR_PTR(err);
+}
+
+static int __alloc_range(struct gpu_buddy *mm,
+ struct list_head *dfs,
+ u64 start, u64 size,
+ struct list_head *blocks,
+ u64 *total_allocated_on_err)
+{
+ struct gpu_buddy_block *block;
+ struct gpu_buddy_block *buddy;
+ u64 total_allocated = 0;
+ LIST_HEAD(allocated);
+ u64 end;
+ int err;
+
+ end = start + size - 1;
+
+ do {
+ u64 block_start;
+ u64 block_end;
+
+ block = list_first_entry_or_null(dfs,
+ struct gpu_buddy_block,
+ tmp_link);
+ if (!block)
+ break;
+
+ list_del(&block->tmp_link);
+
+ block_start = gpu_buddy_block_offset(block);
+ block_end = block_start + gpu_buddy_block_size(mm, block) - 1;
+
+ if (!overlaps(start, end, block_start, block_end))
+ continue;
+
+ if (gpu_buddy_block_is_allocated(block)) {
+ err = -ENOSPC;
+ goto err_free;
+ }
+
+ if (contains(start, end, block_start, block_end)) {
+ if (gpu_buddy_block_is_free(block)) {
+ mark_allocated(mm, block);
+ total_allocated += gpu_buddy_block_size(mm, block);
+ mm->avail -= gpu_buddy_block_size(mm, block);
+ if (gpu_buddy_block_is_clear(block))
+ mm->clear_avail -= gpu_buddy_block_size(mm, block);
+ list_add_tail(&block->link, &allocated);
+ continue;
+ } else if (!mm->clear_avail) {
+ err = -ENOSPC;
+ goto err_free;
+ }
+ }
+
+ if (!gpu_buddy_block_is_split(block)) {
+ err = split_block(mm, block);
+ if (unlikely(err))
+ goto err_undo;
+ }
+
+ list_add(&block->right->tmp_link, dfs);
+ list_add(&block->left->tmp_link, dfs);
+ } while (1);
+
+ if (total_allocated < size) {
+ err = -ENOSPC;
+ goto err_free;
+ }
+
+ list_splice_tail(&allocated, blocks);
+
+ return 0;
+
+err_undo:
+ /*
+ * We really don't want to leave around a bunch of split blocks, since
+ * bigger is better, so make sure we merge everything back before we
+ * free the allocated blocks.
+ */
+ buddy = __get_buddy(block);
+ if (buddy &&
+ (gpu_buddy_block_is_free(block) &&
+ gpu_buddy_block_is_free(buddy)))
+ __gpu_buddy_free(mm, block, false);
+
+err_free:
+ if (err == -ENOSPC && total_allocated_on_err) {
+ list_splice_tail(&allocated, blocks);
+ *total_allocated_on_err = total_allocated;
+ } else {
+ gpu_buddy_free_list_internal(mm, &allocated);
+ }
+
+ return err;
+}
+
+static int __gpu_buddy_alloc_range(struct gpu_buddy *mm,
+ u64 start,
+ u64 size,
+ u64 *total_allocated_on_err,
+ struct list_head *blocks)
+{
+ LIST_HEAD(dfs);
+ int i;
+
+ for (i = 0; i < mm->n_roots; ++i)
+ list_add_tail(&mm->roots[i]->tmp_link, &dfs);
+
+ return __alloc_range(mm, &dfs, start, size,
+ blocks, total_allocated_on_err);
+}
+
+static int __alloc_contig_try_harder(struct gpu_buddy *mm,
+ u64 size,
+ u64 min_block_size,
+ struct list_head *blocks)
+{
+ u64 rhs_offset, lhs_offset, lhs_size, filled;
+ struct gpu_buddy_block *block;
+ unsigned int tree, order;
+ LIST_HEAD(blocks_lhs);
+ unsigned long pages;
+ u64 modify_size;
+ int err;
+
+ modify_size = rounddown_pow_of_two(size);
+ pages = modify_size >> ilog2(mm->chunk_size);
+ order = fls(pages) - 1;
+ if (order == 0)
+ return -ENOSPC;
+
+ for_each_free_tree(tree) {
+ struct rb_root *root;
+ struct rb_node *iter;
+
+ root = &mm->free_trees[tree][order];
+ if (rbtree_is_empty(root))
+ continue;
+
+ iter = rb_last(root);
+ while (iter) {
+ block = rbtree_get_free_block(iter);
+
+ /* Allocate blocks traversing RHS */
+ rhs_offset = gpu_buddy_block_offset(block);
+ err = __gpu_buddy_alloc_range(mm, rhs_offset, size,
+ &filled, blocks);
+ if (!err || err != -ENOSPC)
+ return err;
+
+ lhs_size = max((size - filled), min_block_size);
+ if (!IS_ALIGNED(lhs_size, min_block_size))
+ lhs_size = round_up(lhs_size, min_block_size);
+
+ /* Allocate blocks traversing LHS */
+ lhs_offset = gpu_buddy_block_offset(block) - lhs_size;
+ err = __gpu_buddy_alloc_range(mm, lhs_offset, lhs_size,
+ NULL, &blocks_lhs);
+ if (!err) {
+ list_splice(&blocks_lhs, blocks);
+ return 0;
+ } else if (err != -ENOSPC) {
+ gpu_buddy_free_list_internal(mm, blocks);
+ return err;
+ }
+ /* Free blocks for the next iteration */
+ gpu_buddy_free_list_internal(mm, blocks);
+
+ iter = rb_prev(iter);
+ }
+ }
+
+ return -ENOSPC;
+}
+
+/**
+ * gpu_buddy_block_trim - free unused pages
+ *
+ * @mm: GPU buddy manager
+ * @start: start address to begin the trimming.
+ * @new_size: original size requested
+ * @blocks: Input and output list of allocated blocks.
+ * MUST contain single block as input to be trimmed.
+ * On success will contain the newly allocated blocks
+ * making up the @new_size. Blocks always appear in
+ * ascending order
+ *
+ * For contiguous allocation, we round up the size to the nearest
+ * power of two value, drivers consume *actual* size, so remaining
+ * portions are unused and can be optionally freed with this function
+ *
+ * Returns:
+ * 0 on success, error code on failure.
+ */
+int gpu_buddy_block_trim(struct gpu_buddy *mm,
+ u64 *start,
+ u64 new_size,
+ struct list_head *blocks)
+{
+ struct gpu_buddy_block *parent;
+ struct gpu_buddy_block *block;
+ u64 block_start, block_end;
+ LIST_HEAD(dfs);
+ u64 new_start;
+ int err;
+
+ if (!list_is_singular(blocks))
+ return -EINVAL;
+
+ block = list_first_entry(blocks,
+ struct gpu_buddy_block,
+ link);
+
+ block_start = gpu_buddy_block_offset(block);
+ block_end = block_start + gpu_buddy_block_size(mm, block);
+
+ if (WARN_ON(!gpu_buddy_block_is_allocated(block)))
+ return -EINVAL;
+
+ if (new_size > gpu_buddy_block_size(mm, block))
+ return -EINVAL;
+
+ if (!new_size || !IS_ALIGNED(new_size, mm->chunk_size))
+ return -EINVAL;
+
+ if (new_size == gpu_buddy_block_size(mm, block))
+ return 0;
+
+ new_start = block_start;
+ if (start) {
+ new_start = *start;
+
+ if (new_start < block_start)
+ return -EINVAL;
+
+ if (!IS_ALIGNED(new_start, mm->chunk_size))
+ return -EINVAL;
+
+ if (range_overflows(new_start, new_size, block_end))
+ return -EINVAL;
+ }
+
+ list_del(&block->link);
+ mark_free(mm, block);
+ mm->avail += gpu_buddy_block_size(mm, block);
+ if (gpu_buddy_block_is_clear(block))
+ mm->clear_avail += gpu_buddy_block_size(mm, block);
+
+ /* Prevent recursively freeing this node */
+ parent = block->parent;
+ block->parent = NULL;
+
+ list_add(&block->tmp_link, &dfs);
+ err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL);
+ if (err) {
+ mark_allocated(mm, block);
+ mm->avail -= gpu_buddy_block_size(mm, block);
+ if (gpu_buddy_block_is_clear(block))
+ mm->clear_avail -= gpu_buddy_block_size(mm, block);
+ list_add(&block->link, blocks);
+ }
+
+ block->parent = parent;
+ return err;
+}
+EXPORT_SYMBOL(gpu_buddy_block_trim);
+
+static struct gpu_buddy_block *
+__gpu_buddy_alloc_blocks(struct gpu_buddy *mm,
+ u64 start, u64 end,
+ unsigned int order,
+ unsigned long flags)
+{
+ if (flags & GPU_BUDDY_RANGE_ALLOCATION)
+ /* Allocate traversing within the range */
+ return __gpu_buddy_alloc_range_bias(mm, start, end,
+ order, flags);
+ else
+ /* Allocate from freetree */
+ return alloc_from_freetree(mm, order, flags);
+}
+
+/**
+ * gpu_buddy_alloc_blocks - allocate power-of-two blocks
+ *
+ * @mm: GPU buddy manager to allocate from
+ * @start: start of the allowed range for this block
+ * @end: end of the allowed range for this block
+ * @size: size of the allocation in bytes
+ * @min_block_size: alignment of the allocation
+ * @blocks: output list head to add allocated blocks
+ * @flags: GPU_BUDDY_*_ALLOCATION flags
+ *
+ * alloc_range_bias() called on range limitations, which traverses
+ * the tree and returns the desired block.
+ *
+ * alloc_from_freetree() called when *no* range restrictions
+ * are enforced, which picks the block from the freetree.
+ *
+ * Returns:
+ * 0 on success, error code on failure.
+ */
+int gpu_buddy_alloc_blocks(struct gpu_buddy *mm,
+ u64 start, u64 end, u64 size,
+ u64 min_block_size,
+ struct list_head *blocks,
+ unsigned long flags)
+{
+ struct gpu_buddy_block *block = NULL;
+ u64 original_size, original_min_size;
+ unsigned int min_order, order;
+ LIST_HEAD(allocated);
+ unsigned long pages;
+ int err;
+
+ if (size < mm->chunk_size)
+ return -EINVAL;
+
+ if (min_block_size < mm->chunk_size)
+ return -EINVAL;
+
+ if (!is_power_of_2(min_block_size))
+ return -EINVAL;
+
+ if (!IS_ALIGNED(start | end | size, mm->chunk_size))
+ return -EINVAL;
+
+ if (end > mm->size)
+ return -EINVAL;
+
+ if (range_overflows(start, size, mm->size))
+ return -EINVAL;
+
+ /* Actual range allocation */
+ if (start + size == end) {
+ if (!IS_ALIGNED(start | end, min_block_size))
+ return -EINVAL;
+
+ return __gpu_buddy_alloc_range(mm, start, size, NULL, blocks);
+ }
+
+ original_size = size;
+ original_min_size = min_block_size;
+
+ /* Roundup the size to power of 2 */
+ if (flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION) {
+ size = roundup_pow_of_two(size);
+ min_block_size = size;
+ /* Align size value to min_block_size */
+ } else if (!IS_ALIGNED(size, min_block_size)) {
+ size = round_up(size, min_block_size);
+ }
+
+ pages = size >> ilog2(mm->chunk_size);
+ order = fls(pages) - 1;
+ min_order = ilog2(min_block_size) - ilog2(mm->chunk_size);
+
+ if (order > mm->max_order || size > mm->size) {
+ if ((flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION) &&
+ !(flags & GPU_BUDDY_RANGE_ALLOCATION))
+ return __alloc_contig_try_harder(mm, original_size,
+ original_min_size, blocks);
+
+ return -EINVAL;
+ }
+
+ do {
+ order = min(order, (unsigned int)fls(pages) - 1);
+ BUG_ON(order > mm->max_order);
+ BUG_ON(order < min_order);
+
+ do {
+ block = __gpu_buddy_alloc_blocks(mm, start,
+ end,
+ order,
+ flags);
+ if (!IS_ERR(block))
+ break;
+
+ if (order-- == min_order) {
+ /* Try allocation through force merge method */
+ if (mm->clear_avail &&
+ !__force_merge(mm, start, end, min_order)) {
+ block = __gpu_buddy_alloc_blocks(mm, start,
+ end,
+ min_order,
+ flags);
+ if (!IS_ERR(block)) {
+ order = min_order;
+ break;
+ }
+ }
+
+ /*
+ * Try contiguous block allocation through
+ * try harder method.
+ */
+ if (flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION &&
+ !(flags & GPU_BUDDY_RANGE_ALLOCATION))
+ return __alloc_contig_try_harder(mm,
+ original_size,
+ original_min_size,
+ blocks);
+ err = -ENOSPC;
+ goto err_free;
+ }
+ } while (1);
+
+ mark_allocated(mm, block);
+ mm->avail -= gpu_buddy_block_size(mm, block);
+ if (gpu_buddy_block_is_clear(block))
+ mm->clear_avail -= gpu_buddy_block_size(mm, block);
+ kmemleak_update_trace(block);
+ list_add_tail(&block->link, &allocated);
+
+ pages -= BIT(order);
+
+ if (!pages)
+ break;
+ } while (1);
+
+ /* Trim the allocated block to the required size */
+ if (!(flags & GPU_BUDDY_TRIM_DISABLE) &&
+ original_size != size) {
+ struct list_head *trim_list;
+ LIST_HEAD(temp);
+ u64 trim_size;
+
+ trim_list = &allocated;
+ trim_size = original_size;
+
+ if (!list_is_singular(&allocated)) {
+ block = list_last_entry(&allocated, typeof(*block), link);
+ list_move(&block->link, &temp);
+ trim_list = &temp;
+ trim_size = gpu_buddy_block_size(mm, block) -
+ (size - original_size);
+ }
+
+ gpu_buddy_block_trim(mm,
+ NULL,
+ trim_size,
+ trim_list);
+
+ if (!list_empty(&temp))
+ list_splice_tail(trim_list, &allocated);
+ }
+
+ list_splice_tail(&allocated, blocks);
+ return 0;
+
+err_free:
+ gpu_buddy_free_list_internal(mm, &allocated);
+ return err;
+}
+EXPORT_SYMBOL(gpu_buddy_alloc_blocks);
+
+/**
+ * gpu_buddy_block_print - print block information
+ *
+ * @mm: GPU buddy manager
+ * @block: GPU buddy block
+ */
+void gpu_buddy_block_print(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ u64 start = gpu_buddy_block_offset(block);
+ u64 size = gpu_buddy_block_size(mm, block);
+
+ pr_info("%#018llx-%#018llx: %llu\n", start, start + size, size);
+}
+EXPORT_SYMBOL(gpu_buddy_block_print);
+
+/**
+ * gpu_buddy_print - print allocator state
+ *
+ * @mm: GPU buddy manager
+ * @p: GPU printer to use
+ */
+void gpu_buddy_print(struct gpu_buddy *mm)
+{
+ int order;
+
+ pr_info("chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n",
+ mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20);
+
+ for (order = mm->max_order; order >= 0; order--) {
+ struct gpu_buddy_block *block, *tmp;
+ struct rb_root *root;
+ u64 count = 0, free;
+ unsigned int tree;
+
+ for_each_free_tree(tree) {
+ root = &mm->free_trees[tree][order];
+
+ rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) {
+ BUG_ON(!gpu_buddy_block_is_free(block));
+ count++;
+ }
+ }
+
+ free = count * (mm->chunk_size << order);
+ if (free < SZ_1M)
+ pr_info("order-%2d free: %8llu KiB, blocks: %llu\n",
+ order, free >> 10, count);
+ else
+ pr_info("order-%2d free: %8llu MiB, blocks: %llu\n",
+ order, free >> 20, count);
+ }
+}
+EXPORT_SYMBOL(gpu_buddy_print);
+
+static void gpu_buddy_module_exit(void)
+{
+ kmem_cache_destroy(slab_blocks);
+}
+
+static int __init gpu_buddy_module_init(void)
+{
+ slab_blocks = KMEM_CACHE(gpu_buddy_block, 0);
+ if (!slab_blocks)
+ return -ENOMEM;
+
+ return 0;
+}
+
+module_init(gpu_buddy_module_init);
+module_exit(gpu_buddy_module_exit);
+
+MODULE_DESCRIPTION("GPU Buddy Allocator");
+MODULE_LICENSE("Dual MIT/GPL");
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -85,7 +85,6 @@ config DRM_KUNIT_TEST
select DRM_EXPORT_FOR_TESTS if m
select DRM_GEM_SHMEM_HELPER
select DRM_KUNIT_TEST_HELPERS
- select DRM_LIB_RANDOM
select PRIME_NUMBERS
default KUNIT_ALL_TESTS
help
@@ -325,6 +324,7 @@ config DRM_GPUVM
config DRM_BUDDY
tristate
depends on DRM
+ select GPU_BUDDY
help
A page based buddy allocator
@@ -507,10 +507,6 @@ config DRM_EXPORT_FOR_TESTS
config DRM_PANEL_BACKLIGHT_QUIRKS
tristate
-config DRM_LIB_RANDOM
- bool
- default n
-
config DRM_PRIVACY_SCREEN
bool
default n
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -75,7 +75,6 @@ drm-y := \
drm_vblank_work.o \
drm_vma_manager.o \
drm_writeback.o
-drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
@@ -55,7 +55,7 @@ static inline void amdgpu_res_first(stru
uint64_t start, uint64_t size,
struct amdgpu_res_cursor *cur)
{
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
struct list_head *head, *next;
struct drm_mm_node *node;
@@ -71,7 +71,7 @@ static inline void amdgpu_res_first(stru
head = &to_amdgpu_vram_mgr_resource(res)->blocks;
block = list_first_entry_or_null(head,
- struct drm_buddy_block,
+ struct gpu_buddy_block,
link);
if (!block)
goto fallback;
@@ -81,7 +81,7 @@ static inline void amdgpu_res_first(stru
next = block->link.next;
if (next != head)
- block = list_entry(next, struct drm_buddy_block, link);
+ block = list_entry(next, struct gpu_buddy_block, link);
}
cur->start = amdgpu_vram_mgr_block_start(block) + start;
@@ -124,7 +124,7 @@ fallback:
*/
static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
{
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
struct drm_mm_node *node;
struct list_head *next;
@@ -145,7 +145,7 @@ static inline void amdgpu_res_next(struc
block = cur->node;
next = block->link.next;
- block = list_entry(next, struct drm_buddy_block, link);
+ block = list_entry(next, struct gpu_buddy_block, link);
cur->node = block;
cur->start = amdgpu_vram_mgr_block_start(block);
@@ -173,7 +173,7 @@ static inline void amdgpu_res_next(struc
*/
static inline bool amdgpu_res_cleared(struct amdgpu_res_cursor *cur)
{
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
switch (cur->mem_type) {
case TTM_PL_VRAM:
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -24,6 +24,7 @@
#include <linux/dma-mapping.h>
#include <drm/ttm/ttm_range_manager.h>
+#include <drm/drm_buddy.h>
#include "amdgpu.h"
#include "amdgpu_vm.h"
@@ -52,15 +53,15 @@ to_amdgpu_device(struct amdgpu_vram_mgr
return container_of(mgr, struct amdgpu_device, mman.vram_mgr);
}
-static inline struct drm_buddy_block *
+static inline struct gpu_buddy_block *
amdgpu_vram_mgr_first_block(struct list_head *list)
{
- return list_first_entry_or_null(list, struct drm_buddy_block, link);
+ return list_first_entry_or_null(list, struct gpu_buddy_block, link);
}
static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head)
{
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
u64 start, size;
block = amdgpu_vram_mgr_first_block(head);
@@ -71,7 +72,7 @@ static inline bool amdgpu_is_vram_mgr_bl
start = amdgpu_vram_mgr_block_start(block);
size = amdgpu_vram_mgr_block_size(block);
- block = list_entry(block->link.next, struct drm_buddy_block, link);
+ block = list_entry(block->link.next, struct gpu_buddy_block, link);
if (start + size != amdgpu_vram_mgr_block_start(block))
return false;
}
@@ -81,7 +82,7 @@ static inline bool amdgpu_is_vram_mgr_bl
static inline u64 amdgpu_vram_mgr_blocks_size(struct list_head *head)
{
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
u64 size = 0;
list_for_each_entry(block, head, link)
@@ -254,7 +255,7 @@ const struct attribute_group amdgpu_vram
* Calculate how many bytes of the DRM BUDDY block are inside visible VRAM
*/
static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
- struct drm_buddy_block *block)
+ struct gpu_buddy_block *block)
{
u64 start = amdgpu_vram_mgr_block_start(block);
u64 end = start + amdgpu_vram_mgr_block_size(block);
@@ -279,7 +280,7 @@ u64 amdgpu_vram_mgr_bo_visible_size(stru
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct ttm_resource *res = bo->tbo.resource;
struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
u64 usage = 0;
if (amdgpu_gmc_vram_full_visible(&adev->gmc))
@@ -299,15 +300,15 @@ static void amdgpu_vram_mgr_do_reserve(s
{
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
struct amdgpu_device *adev = to_amdgpu_device(mgr);
- struct drm_buddy *mm = &mgr->mm;
+ struct gpu_buddy *mm = &mgr->mm;
struct amdgpu_vram_reservation *rsv, *temp;
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
uint64_t vis_usage;
list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks) {
- if (drm_buddy_alloc_blocks(mm, rsv->start, rsv->start + rsv->size,
+ if (gpu_buddy_alloc_blocks(mm, rsv->start, rsv->start + rsv->size,
rsv->size, mm->chunk_size, &rsv->allocated,
- DRM_BUDDY_RANGE_ALLOCATION))
+ GPU_BUDDY_RANGE_ALLOCATION))
continue;
block = amdgpu_vram_mgr_first_block(&rsv->allocated);
@@ -460,8 +461,8 @@ static int amdgpu_vram_mgr_new(struct tt
struct amdgpu_vram_mgr_resource *vres;
u64 size, remaining_size, lpfn, fpfn;
unsigned int adjust_dcc_size = 0;
- struct drm_buddy *mm = &mgr->mm;
- struct drm_buddy_block *block;
+ struct gpu_buddy *mm = &mgr->mm;
+ struct gpu_buddy_block *block;
unsigned long pages_per_block;
int r;
@@ -503,17 +504,17 @@ static int amdgpu_vram_mgr_new(struct tt
INIT_LIST_HEAD(&vres->blocks);
if (place->flags & TTM_PL_FLAG_TOPDOWN)
- vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
+ vres->flags |= GPU_BUDDY_TOPDOWN_ALLOCATION;
if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)
- vres->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION;
+ vres->flags |= GPU_BUDDY_CONTIGUOUS_ALLOCATION;
if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED)
- vres->flags |= DRM_BUDDY_CLEAR_ALLOCATION;
+ vres->flags |= GPU_BUDDY_CLEAR_ALLOCATION;
if (fpfn || lpfn != mgr->mm.size)
/* Allocate blocks in desired range */
- vres->flags |= DRM_BUDDY_RANGE_ALLOCATION;
+ vres->flags |= GPU_BUDDY_RANGE_ALLOCATION;
if (bo->flags & AMDGPU_GEM_CREATE_GFX12_DCC &&
adev->gmc.gmc_funcs->get_dcc_alignment)
@@ -526,7 +527,7 @@ static int amdgpu_vram_mgr_new(struct tt
dcc_size = roundup_pow_of_two(vres->base.size + adjust_dcc_size);
remaining_size = (u64)dcc_size;
- vres->flags |= DRM_BUDDY_TRIM_DISABLE;
+ vres->flags |= GPU_BUDDY_TRIM_DISABLE;
}
mutex_lock(&mgr->lock);
@@ -546,7 +547,7 @@ static int amdgpu_vram_mgr_new(struct tt
BUG_ON(min_block_size < mm->chunk_size);
- r = drm_buddy_alloc_blocks(mm, fpfn,
+ r = gpu_buddy_alloc_blocks(mm, fpfn,
lpfn,
size,
min_block_size,
@@ -555,7 +556,7 @@ static int amdgpu_vram_mgr_new(struct tt
if (unlikely(r == -ENOSPC) && pages_per_block == ~0ul &&
!(place->flags & TTM_PL_FLAG_CONTIGUOUS)) {
- vres->flags &= ~DRM_BUDDY_CONTIGUOUS_ALLOCATION;
+ vres->flags &= ~GPU_BUDDY_CONTIGUOUS_ALLOCATION;
pages_per_block = max_t(u32, 2UL << (20UL - PAGE_SHIFT),
tbo->page_alignment);
@@ -572,7 +573,7 @@ static int amdgpu_vram_mgr_new(struct tt
}
if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS && adjust_dcc_size) {
- struct drm_buddy_block *dcc_block;
+ struct gpu_buddy_block *dcc_block;
unsigned long dcc_start;
u64 trim_start;
@@ -582,7 +583,7 @@ static int amdgpu_vram_mgr_new(struct tt
roundup((unsigned long)amdgpu_vram_mgr_block_start(dcc_block),
adjust_dcc_size);
trim_start = (u64)dcc_start;
- drm_buddy_block_trim(mm, &trim_start,
+ gpu_buddy_block_trim(mm, &trim_start,
(u64)vres->base.size,
&vres->blocks);
}
@@ -620,7 +621,7 @@ static int amdgpu_vram_mgr_new(struct tt
return 0;
error_free_blocks:
- drm_buddy_free_list(mm, &vres->blocks, 0);
+ gpu_buddy_free_list(mm, &vres->blocks, 0);
mutex_unlock(&mgr->lock);
error_fini:
ttm_resource_fini(man, &vres->base);
@@ -643,15 +644,15 @@ static void amdgpu_vram_mgr_del(struct t
struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
struct amdgpu_device *adev = to_amdgpu_device(mgr);
- struct drm_buddy *mm = &mgr->mm;
- struct drm_buddy_block *block;
+ struct gpu_buddy *mm = &mgr->mm;
+ struct gpu_buddy_block *block;
uint64_t vis_usage = 0;
mutex_lock(&mgr->lock);
list_for_each_entry(block, &vres->blocks, link)
vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
- drm_buddy_free_list(mm, &vres->blocks, vres->flags);
+ gpu_buddy_free_list(mm, &vres->blocks, vres->flags);
amdgpu_vram_mgr_do_reserve(man);
mutex_unlock(&mgr->lock);
@@ -690,7 +691,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amd
if (!*sgt)
return -ENOMEM;
- /* Determine the number of DRM_BUDDY blocks to export */
+ /* Determine the number of GPU_BUDDY blocks to export */
amdgpu_res_first(res, offset, length, &cursor);
while (cursor.remaining) {
num_entries++;
@@ -706,10 +707,10 @@ int amdgpu_vram_mgr_alloc_sgt(struct amd
sg->length = 0;
/*
- * Walk down DRM_BUDDY blocks to populate scatterlist nodes
- * @note: Use iterator api to get first the DRM_BUDDY block
+ * Walk down GPU_BUDDY blocks to populate scatterlist nodes
+ * @note: Use iterator api to get first the GPU_BUDDY block
* and the number of bytes from it. Access the following
- * DRM_BUDDY block(s) if more buffer needs to exported
+ * GPU_BUDDY block(s) if more buffer needs to exported
*/
amdgpu_res_first(res, offset, length, &cursor);
for_each_sgtable_sg((*sgt), sg, i) {
@@ -794,10 +795,10 @@ uint64_t amdgpu_vram_mgr_vis_usage(struc
void amdgpu_vram_mgr_clear_reset_blocks(struct amdgpu_device *adev)
{
struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
- struct drm_buddy *mm = &mgr->mm;
+ struct gpu_buddy *mm = &mgr->mm;
mutex_lock(&mgr->lock);
- drm_buddy_reset_clear(mm, false);
+ gpu_buddy_reset_clear(mm, false);
mutex_unlock(&mgr->lock);
}
@@ -817,7 +818,7 @@ static bool amdgpu_vram_mgr_intersects(s
size_t size)
{
struct amdgpu_vram_mgr_resource *mgr = to_amdgpu_vram_mgr_resource(res);
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
/* Check each drm buddy block individually */
list_for_each_entry(block, &mgr->blocks, link) {
@@ -850,7 +851,7 @@ static bool amdgpu_vram_mgr_compatible(s
size_t size)
{
struct amdgpu_vram_mgr_resource *mgr = to_amdgpu_vram_mgr_resource(res);
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
/* Check each drm buddy block individually */
list_for_each_entry(block, &mgr->blocks, link) {
@@ -879,7 +880,7 @@ static void amdgpu_vram_mgr_debug(struct
struct drm_printer *printer)
{
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
- struct drm_buddy *mm = &mgr->mm;
+ struct gpu_buddy *mm = &mgr->mm;
struct amdgpu_vram_reservation *rsv;
drm_printf(printer, " vis usage:%llu\n",
@@ -938,7 +939,7 @@ int amdgpu_vram_mgr_init(struct amdgpu_d
if (!adev->gmc.is_app_apu) {
man->func = &amdgpu_vram_mgr_func;
- err = drm_buddy_init(&mgr->mm, man->size, PAGE_SIZE);
+ err = gpu_buddy_init(&mgr->mm, man->size, PAGE_SIZE);
if (err)
return err;
} else {
@@ -977,11 +978,11 @@ void amdgpu_vram_mgr_fini(struct amdgpu_
kfree(rsv);
list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) {
- drm_buddy_free_list(&mgr->mm, &rsv->allocated, 0);
+ gpu_buddy_free_list(&mgr->mm, &rsv->allocated, 0);
kfree(rsv);
}
if (!adev->gmc.is_app_apu)
- drm_buddy_fini(&mgr->mm);
+ gpu_buddy_fini(&mgr->mm);
mutex_unlock(&mgr->lock);
ttm_resource_manager_cleanup(man);
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
@@ -24,11 +24,11 @@
#ifndef __AMDGPU_VRAM_MGR_H__
#define __AMDGPU_VRAM_MGR_H__
-#include <drm/drm_buddy.h>
+#include <linux/gpu_buddy.h>
struct amdgpu_vram_mgr {
struct ttm_resource_manager manager;
- struct drm_buddy mm;
+ struct gpu_buddy mm;
/* protects access to buffer objects */
struct mutex lock;
struct list_head reservations_pending;
@@ -43,19 +43,19 @@ struct amdgpu_vram_mgr_resource {
unsigned long flags;
};
-static inline u64 amdgpu_vram_mgr_block_start(struct drm_buddy_block *block)
+static inline u64 amdgpu_vram_mgr_block_start(struct gpu_buddy_block *block)
{
- return drm_buddy_block_offset(block);
+ return gpu_buddy_block_offset(block);
}
-static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block)
+static inline u64 amdgpu_vram_mgr_block_size(struct gpu_buddy_block *block)
{
- return (u64)PAGE_SIZE << drm_buddy_block_order(block);
+ return (u64)PAGE_SIZE << gpu_buddy_block_order(block);
}
-static inline bool amdgpu_vram_mgr_is_cleared(struct drm_buddy_block *block)
+static inline bool amdgpu_vram_mgr_is_cleared(struct gpu_buddy_block *block)
{
- return drm_buddy_block_is_clear(block);
+ return gpu_buddy_block_is_clear(block);
}
static inline struct amdgpu_vram_mgr_resource *
@@ -66,7 +66,7 @@ to_amdgpu_vram_mgr_resource(struct ttm_r
static inline void amdgpu_vram_mgr_set_cleared(struct ttm_resource *res)
{
- to_amdgpu_vram_mgr_resource(res)->flags |= DRM_BUDDY_CLEARED;
+ to_amdgpu_vram_mgr_resource(res)->flags |= GPU_BUDDY_CLEARED;
}
#endif
--- a/drivers/gpu/drm/drm_buddy.c
+++ b/drivers/gpu/drm/drm_buddy.c
@@ -3,1252 +3,16 @@
* Copyright © 2021 Intel Corporation
*/
+#include <kunit/test-bug.h>
+
+#include <linux/export.h>
#include <linux/kmemleak.h>
#include <linux/module.h>
#include <linux/sizes.h>
+#include <linux/gpu_buddy.h>
#include <drm/drm_buddy.h>
-
-enum drm_buddy_free_tree {
- DRM_BUDDY_CLEAR_TREE = 0,
- DRM_BUDDY_DIRTY_TREE,
- DRM_BUDDY_MAX_FREE_TREES,
-};
-
-static struct kmem_cache *slab_blocks;
-
-#define for_each_free_tree(tree) \
- for ((tree) = 0; (tree) < DRM_BUDDY_MAX_FREE_TREES; (tree)++)
-
-static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm,
- struct drm_buddy_block *parent,
- unsigned int order,
- u64 offset)
-{
- struct drm_buddy_block *block;
-
- BUG_ON(order > DRM_BUDDY_MAX_ORDER);
-
- block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL);
- if (!block)
- return NULL;
-
- block->header = offset;
- block->header |= order;
- block->parent = parent;
-
- RB_CLEAR_NODE(&block->rb);
-
- BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED);
- return block;
-}
-
-static void drm_block_free(struct drm_buddy *mm,
- struct drm_buddy_block *block)
-{
- kmem_cache_free(slab_blocks, block);
-}
-
-static enum drm_buddy_free_tree
-get_block_tree(struct drm_buddy_block *block)
-{
- return drm_buddy_block_is_clear(block) ?
- DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
-}
-
-static struct drm_buddy_block *
-rbtree_get_free_block(const struct rb_node *node)
-{
- return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL;
-}
-
-static struct drm_buddy_block *
-rbtree_last_free_block(struct rb_root *root)
-{
- return rbtree_get_free_block(rb_last(root));
-}
-
-static bool rbtree_is_empty(struct rb_root *root)
-{
- return RB_EMPTY_ROOT(root);
-}
-
-static bool drm_buddy_block_offset_less(const struct drm_buddy_block *block,
- const struct drm_buddy_block *node)
-{
- return drm_buddy_block_offset(block) < drm_buddy_block_offset(node);
-}
-
-static bool rbtree_block_offset_less(struct rb_node *block,
- const struct rb_node *node)
-{
- return drm_buddy_block_offset_less(rbtree_get_free_block(block),
- rbtree_get_free_block(node));
-}
-
-static void rbtree_insert(struct drm_buddy *mm,
- struct drm_buddy_block *block,
- enum drm_buddy_free_tree tree)
-{
- rb_add(&block->rb,
- &mm->free_trees[tree][drm_buddy_block_order(block)],
- rbtree_block_offset_less);
-}
-
-static void rbtree_remove(struct drm_buddy *mm,
- struct drm_buddy_block *block)
-{
- unsigned int order = drm_buddy_block_order(block);
- enum drm_buddy_free_tree tree;
- struct rb_root *root;
-
- tree = get_block_tree(block);
- root = &mm->free_trees[tree][order];
-
- rb_erase(&block->rb, root);
- RB_CLEAR_NODE(&block->rb);
-}
-
-static void clear_reset(struct drm_buddy_block *block)
-{
- block->header &= ~DRM_BUDDY_HEADER_CLEAR;
-}
-
-static void mark_cleared(struct drm_buddy_block *block)
-{
- block->header |= DRM_BUDDY_HEADER_CLEAR;
-}
-
-static void mark_allocated(struct drm_buddy *mm,
- struct drm_buddy_block *block)
-{
- block->header &= ~DRM_BUDDY_HEADER_STATE;
- block->header |= DRM_BUDDY_ALLOCATED;
-
- rbtree_remove(mm, block);
-}
-
-static void mark_free(struct drm_buddy *mm,
- struct drm_buddy_block *block)
-{
- enum drm_buddy_free_tree tree;
-
- block->header &= ~DRM_BUDDY_HEADER_STATE;
- block->header |= DRM_BUDDY_FREE;
-
- tree = get_block_tree(block);
- rbtree_insert(mm, block, tree);
-}
-
-static void mark_split(struct drm_buddy *mm,
- struct drm_buddy_block *block)
-{
- block->header &= ~DRM_BUDDY_HEADER_STATE;
- block->header |= DRM_BUDDY_SPLIT;
-
- rbtree_remove(mm, block);
-}
-
-static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
-{
- return s1 <= e2 && e1 >= s2;
-}
-
-static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2)
-{
- return s1 <= s2 && e1 >= e2;
-}
-
-static struct drm_buddy_block *
-__get_buddy(struct drm_buddy_block *block)
-{
- struct drm_buddy_block *parent;
-
- parent = block->parent;
- if (!parent)
- return NULL;
-
- if (parent->left == block)
- return parent->right;
-
- return parent->left;
-}
-
-static unsigned int __drm_buddy_free(struct drm_buddy *mm,
- struct drm_buddy_block *block,
- bool force_merge)
-{
- struct drm_buddy_block *parent;
- unsigned int order;
-
- while ((parent = block->parent)) {
- struct drm_buddy_block *buddy;
-
- buddy = __get_buddy(block);
-
- if (!drm_buddy_block_is_free(buddy))
- break;
-
- if (!force_merge) {
- /*
- * Check the block and its buddy clear state and exit
- * the loop if they both have the dissimilar state.
- */
- if (drm_buddy_block_is_clear(block) !=
- drm_buddy_block_is_clear(buddy))
- break;
-
- if (drm_buddy_block_is_clear(block))
- mark_cleared(parent);
- }
-
- rbtree_remove(mm, buddy);
- if (force_merge && drm_buddy_block_is_clear(buddy))
- mm->clear_avail -= drm_buddy_block_size(mm, buddy);
-
- drm_block_free(mm, block);
- drm_block_free(mm, buddy);
-
- block = parent;
- }
-
- order = drm_buddy_block_order(block);
- mark_free(mm, block);
-
- return order;
-}
-
-static int __force_merge(struct drm_buddy *mm,
- u64 start,
- u64 end,
- unsigned int min_order)
-{
- unsigned int tree, order;
- int i;
-
- if (!min_order)
- return -ENOMEM;
-
- if (min_order > mm->max_order)
- return -EINVAL;
-
- for_each_free_tree(tree) {
- for (i = min_order - 1; i >= 0; i--) {
- struct rb_node *iter = rb_last(&mm->free_trees[tree][i]);
-
- while (iter) {
- struct drm_buddy_block *block, *buddy;
- u64 block_start, block_end;
-
- block = rbtree_get_free_block(iter);
- iter = rb_prev(iter);
-
- if (!block || !block->parent)
- continue;
-
- block_start = drm_buddy_block_offset(block);
- block_end = block_start + drm_buddy_block_size(mm, block) - 1;
-
- if (!contains(start, end, block_start, block_end))
- continue;
-
- buddy = __get_buddy(block);
- if (!drm_buddy_block_is_free(buddy))
- continue;
-
- WARN_ON(drm_buddy_block_is_clear(block) ==
- drm_buddy_block_is_clear(buddy));
-
- /*
- * Advance to the next node when the current node is the buddy,
- * as freeing the block will also remove its buddy from the tree.
- */
- if (iter == &buddy->rb)
- iter = rb_prev(iter);
-
- rbtree_remove(mm, block);
- if (drm_buddy_block_is_clear(block))
- mm->clear_avail -= drm_buddy_block_size(mm, block);
-
- order = __drm_buddy_free(mm, block, true);
- if (order >= min_order)
- return 0;
- }
- }
- }
-
- return -ENOMEM;
-}
-
-/**
- * drm_buddy_init - init memory manager
- *
- * @mm: DRM buddy manager to initialize
- * @size: size in bytes to manage
- * @chunk_size: minimum page size in bytes for our allocations
- *
- * Initializes the memory manager and its resources.
- *
- * Returns:
- * 0 on success, error code on failure.
- */
-int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size)
-{
- unsigned int i, j, root_count = 0;
- u64 offset = 0;
-
- if (size < chunk_size)
- return -EINVAL;
-
- if (chunk_size < SZ_4K)
- return -EINVAL;
-
- if (!is_power_of_2(chunk_size))
- return -EINVAL;
-
- size = round_down(size, chunk_size);
-
- mm->size = size;
- mm->avail = size;
- mm->clear_avail = 0;
- mm->chunk_size = chunk_size;
- mm->max_order = ilog2(size) - ilog2(chunk_size);
-
- BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER);
-
- mm->free_trees = kmalloc_array(DRM_BUDDY_MAX_FREE_TREES,
- sizeof(*mm->free_trees),
- GFP_KERNEL);
- if (!mm->free_trees)
- return -ENOMEM;
-
- for_each_free_tree(i) {
- mm->free_trees[i] = kmalloc_array(mm->max_order + 1,
- sizeof(struct rb_root),
- GFP_KERNEL);
- if (!mm->free_trees[i])
- goto out_free_tree;
-
- for (j = 0; j <= mm->max_order; ++j)
- mm->free_trees[i][j] = RB_ROOT;
- }
-
- mm->n_roots = hweight64(size);
-
- mm->roots = kmalloc_array(mm->n_roots,
- sizeof(struct drm_buddy_block *),
- GFP_KERNEL);
- if (!mm->roots)
- goto out_free_tree;
-
- /*
- * Split into power-of-two blocks, in case we are given a size that is
- * not itself a power-of-two.
- */
- do {
- struct drm_buddy_block *root;
- unsigned int order;
- u64 root_size;
-
- order = ilog2(size) - ilog2(chunk_size);
- root_size = chunk_size << order;
-
- root = drm_block_alloc(mm, NULL, order, offset);
- if (!root)
- goto out_free_roots;
-
- mark_free(mm, root);
-
- BUG_ON(root_count > mm->max_order);
- BUG_ON(drm_buddy_block_size(mm, root) < chunk_size);
-
- mm->roots[root_count] = root;
-
- offset += root_size;
- size -= root_size;
- root_count++;
- } while (size);
-
- return 0;
-
-out_free_roots:
- while (root_count--)
- drm_block_free(mm, mm->roots[root_count]);
- kfree(mm->roots);
-out_free_tree:
- while (i--)
- kfree(mm->free_trees[i]);
- kfree(mm->free_trees);
- return -ENOMEM;
-}
-EXPORT_SYMBOL(drm_buddy_init);
-
-/**
- * drm_buddy_fini - tear down the memory manager
- *
- * @mm: DRM buddy manager to free
- *
- * Cleanup memory manager resources and the freetree
- */
-void drm_buddy_fini(struct drm_buddy *mm)
-{
- u64 root_size, size, start;
- unsigned int order;
- int i;
-
- size = mm->size;
-
- for (i = 0; i < mm->n_roots; ++i) {
- order = ilog2(size) - ilog2(mm->chunk_size);
- start = drm_buddy_block_offset(mm->roots[i]);
- __force_merge(mm, start, start + size, order);
-
- WARN_ON(!drm_buddy_block_is_free(mm->roots[i]));
- drm_block_free(mm, mm->roots[i]);
-
- root_size = mm->chunk_size << order;
- size -= root_size;
- }
-
- WARN_ON(mm->avail != mm->size);
-
- for_each_free_tree(i)
- kfree(mm->free_trees[i]);
- kfree(mm->free_trees);
- kfree(mm->roots);
-}
-EXPORT_SYMBOL(drm_buddy_fini);
-
-static int split_block(struct drm_buddy *mm,
- struct drm_buddy_block *block)
-{
- unsigned int block_order = drm_buddy_block_order(block) - 1;
- u64 offset = drm_buddy_block_offset(block);
-
- BUG_ON(!drm_buddy_block_is_free(block));
- BUG_ON(!drm_buddy_block_order(block));
-
- block->left = drm_block_alloc(mm, block, block_order, offset);
- if (!block->left)
- return -ENOMEM;
-
- block->right = drm_block_alloc(mm, block, block_order,
- offset + (mm->chunk_size << block_order));
- if (!block->right) {
- drm_block_free(mm, block->left);
- return -ENOMEM;
- }
-
- mark_split(mm, block);
-
- if (drm_buddy_block_is_clear(block)) {
- mark_cleared(block->left);
- mark_cleared(block->right);
- clear_reset(block);
- }
-
- mark_free(mm, block->left);
- mark_free(mm, block->right);
-
- return 0;
-}
-
-/**
- * drm_get_buddy - get buddy address
- *
- * @block: DRM buddy block
- *
- * Returns the corresponding buddy block for @block, or NULL
- * if this is a root block and can't be merged further.
- * Requires some kind of locking to protect against
- * any concurrent allocate and free operations.
- */
-struct drm_buddy_block *
-drm_get_buddy(struct drm_buddy_block *block)
-{
- return __get_buddy(block);
-}
-EXPORT_SYMBOL(drm_get_buddy);
-
-/**
- * drm_buddy_reset_clear - reset blocks clear state
- *
- * @mm: DRM buddy manager
- * @is_clear: blocks clear state
- *
- * Reset the clear state based on @is_clear value for each block
- * in the freetree.
- */
-void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear)
-{
- enum drm_buddy_free_tree src_tree, dst_tree;
- u64 root_size, size, start;
- unsigned int order;
- int i;
-
- size = mm->size;
- for (i = 0; i < mm->n_roots; ++i) {
- order = ilog2(size) - ilog2(mm->chunk_size);
- start = drm_buddy_block_offset(mm->roots[i]);
- __force_merge(mm, start, start + size, order);
-
- root_size = mm->chunk_size << order;
- size -= root_size;
- }
-
- src_tree = is_clear ? DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE;
- dst_tree = is_clear ? DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
-
- for (i = 0; i <= mm->max_order; ++i) {
- struct rb_root *root = &mm->free_trees[src_tree][i];
- struct drm_buddy_block *block, *tmp;
-
- rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) {
- rbtree_remove(mm, block);
- if (is_clear) {
- mark_cleared(block);
- mm->clear_avail += drm_buddy_block_size(mm, block);
- } else {
- clear_reset(block);
- mm->clear_avail -= drm_buddy_block_size(mm, block);
- }
-
- rbtree_insert(mm, block, dst_tree);
- }
- }
-}
-EXPORT_SYMBOL(drm_buddy_reset_clear);
-
-/**
- * drm_buddy_free_block - free a block
- *
- * @mm: DRM buddy manager
- * @block: block to be freed
- */
-void drm_buddy_free_block(struct drm_buddy *mm,
- struct drm_buddy_block *block)
-{
- BUG_ON(!drm_buddy_block_is_allocated(block));
- mm->avail += drm_buddy_block_size(mm, block);
- if (drm_buddy_block_is_clear(block))
- mm->clear_avail += drm_buddy_block_size(mm, block);
-
- __drm_buddy_free(mm, block, false);
-}
-EXPORT_SYMBOL(drm_buddy_free_block);
-
-static void __drm_buddy_free_list(struct drm_buddy *mm,
- struct list_head *objects,
- bool mark_clear,
- bool mark_dirty)
-{
- struct drm_buddy_block *block, *on;
-
- WARN_ON(mark_dirty && mark_clear);
-
- list_for_each_entry_safe(block, on, objects, link) {
- if (mark_clear)
- mark_cleared(block);
- else if (mark_dirty)
- clear_reset(block);
- drm_buddy_free_block(mm, block);
- cond_resched();
- }
- INIT_LIST_HEAD(objects);
-}
-
-static void drm_buddy_free_list_internal(struct drm_buddy *mm,
- struct list_head *objects)
-{
- /*
- * Don't touch the clear/dirty bit, since allocation is still internal
- * at this point. For example we might have just failed part of the
- * allocation.
- */
- __drm_buddy_free_list(mm, objects, false, false);
-}
-
-/**
- * drm_buddy_free_list - free blocks
- *
- * @mm: DRM buddy manager
- * @objects: input list head to free blocks
- * @flags: optional flags like DRM_BUDDY_CLEARED
- */
-void drm_buddy_free_list(struct drm_buddy *mm,
- struct list_head *objects,
- unsigned int flags)
-{
- bool mark_clear = flags & DRM_BUDDY_CLEARED;
-
- __drm_buddy_free_list(mm, objects, mark_clear, !mark_clear);
-}
-EXPORT_SYMBOL(drm_buddy_free_list);
-
-static bool block_incompatible(struct drm_buddy_block *block, unsigned int flags)
-{
- bool needs_clear = flags & DRM_BUDDY_CLEAR_ALLOCATION;
-
- return needs_clear != drm_buddy_block_is_clear(block);
-}
-
-static struct drm_buddy_block *
-__alloc_range_bias(struct drm_buddy *mm,
- u64 start, u64 end,
- unsigned int order,
- unsigned long flags,
- bool fallback)
-{
- u64 req_size = mm->chunk_size << order;
- struct drm_buddy_block *block;
- struct drm_buddy_block *buddy;
- LIST_HEAD(dfs);
- int err;
- int i;
-
- end = end - 1;
-
- for (i = 0; i < mm->n_roots; ++i)
- list_add_tail(&mm->roots[i]->tmp_link, &dfs);
-
- do {
- u64 block_start;
- u64 block_end;
-
- block = list_first_entry_or_null(&dfs,
- struct drm_buddy_block,
- tmp_link);
- if (!block)
- break;
-
- list_del(&block->tmp_link);
-
- if (drm_buddy_block_order(block) < order)
- continue;
-
- block_start = drm_buddy_block_offset(block);
- block_end = block_start + drm_buddy_block_size(mm, block) - 1;
-
- if (!overlaps(start, end, block_start, block_end))
- continue;
-
- if (drm_buddy_block_is_allocated(block))
- continue;
-
- if (block_start < start || block_end > end) {
- u64 adjusted_start = max(block_start, start);
- u64 adjusted_end = min(block_end, end);
-
- if (round_down(adjusted_end + 1, req_size) <=
- round_up(adjusted_start, req_size))
- continue;
- }
-
- if (!fallback && block_incompatible(block, flags))
- continue;
-
- if (contains(start, end, block_start, block_end) &&
- order == drm_buddy_block_order(block)) {
- /*
- * Find the free block within the range.
- */
- if (drm_buddy_block_is_free(block))
- return block;
-
- continue;
- }
-
- if (!drm_buddy_block_is_split(block)) {
- err = split_block(mm, block);
- if (unlikely(err))
- goto err_undo;
- }
-
- list_add(&block->right->tmp_link, &dfs);
- list_add(&block->left->tmp_link, &dfs);
- } while (1);
-
- return ERR_PTR(-ENOSPC);
-
-err_undo:
- /*
- * We really don't want to leave around a bunch of split blocks, since
- * bigger is better, so make sure we merge everything back before we
- * free the allocated blocks.
- */
- buddy = __get_buddy(block);
- if (buddy &&
- (drm_buddy_block_is_free(block) &&
- drm_buddy_block_is_free(buddy)))
- __drm_buddy_free(mm, block, false);
- return ERR_PTR(err);
-}
-
-static struct drm_buddy_block *
-__drm_buddy_alloc_range_bias(struct drm_buddy *mm,
- u64 start, u64 end,
- unsigned int order,
- unsigned long flags)
-{
- struct drm_buddy_block *block;
- bool fallback = false;
-
- block = __alloc_range_bias(mm, start, end, order,
- flags, fallback);
- if (IS_ERR(block))
- return __alloc_range_bias(mm, start, end, order,
- flags, !fallback);
-
- return block;
-}
-
-static struct drm_buddy_block *
-get_maxblock(struct drm_buddy *mm,
- unsigned int order,
- enum drm_buddy_free_tree tree)
-{
- struct drm_buddy_block *max_block = NULL, *block = NULL;
- struct rb_root *root;
- unsigned int i;
-
- for (i = order; i <= mm->max_order; ++i) {
- root = &mm->free_trees[tree][i];
- block = rbtree_last_free_block(root);
- if (!block)
- continue;
-
- if (!max_block) {
- max_block = block;
- continue;
- }
-
- if (drm_buddy_block_offset(block) >
- drm_buddy_block_offset(max_block)) {
- max_block = block;
- }
- }
-
- return max_block;
-}
-
-static struct drm_buddy_block *
-alloc_from_freetree(struct drm_buddy *mm,
- unsigned int order,
- unsigned long flags)
-{
- struct drm_buddy_block *block = NULL;
- struct rb_root *root;
- enum drm_buddy_free_tree tree;
- unsigned int tmp;
- int err;
-
- tree = (flags & DRM_BUDDY_CLEAR_ALLOCATION) ?
- DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
-
- if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
- block = get_maxblock(mm, order, tree);
- if (block)
- /* Store the obtained block order */
- tmp = drm_buddy_block_order(block);
- } else {
- for (tmp = order; tmp <= mm->max_order; ++tmp) {
- /* Get RB tree root for this order and tree */
- root = &mm->free_trees[tree][tmp];
- block = rbtree_last_free_block(root);
- if (block)
- break;
- }
- }
-
- if (!block) {
- /* Try allocating from the other tree */
- tree = (tree == DRM_BUDDY_CLEAR_TREE) ?
- DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE;
-
- for (tmp = order; tmp <= mm->max_order; ++tmp) {
- root = &mm->free_trees[tree][tmp];
- block = rbtree_last_free_block(root);
- if (block)
- break;
- }
-
- if (!block)
- return ERR_PTR(-ENOSPC);
- }
-
- BUG_ON(!drm_buddy_block_is_free(block));
-
- while (tmp != order) {
- err = split_block(mm, block);
- if (unlikely(err))
- goto err_undo;
-
- block = block->right;
- tmp--;
- }
- return block;
-
-err_undo:
- if (tmp != order)
- __drm_buddy_free(mm, block, false);
- return ERR_PTR(err);
-}
-
-static int __alloc_range(struct drm_buddy *mm,
- struct list_head *dfs,
- u64 start, u64 size,
- struct list_head *blocks,
- u64 *total_allocated_on_err)
-{
- struct drm_buddy_block *block;
- struct drm_buddy_block *buddy;
- u64 total_allocated = 0;
- LIST_HEAD(allocated);
- u64 end;
- int err;
-
- end = start + size - 1;
-
- do {
- u64 block_start;
- u64 block_end;
-
- block = list_first_entry_or_null(dfs,
- struct drm_buddy_block,
- tmp_link);
- if (!block)
- break;
-
- list_del(&block->tmp_link);
-
- block_start = drm_buddy_block_offset(block);
- block_end = block_start + drm_buddy_block_size(mm, block) - 1;
-
- if (!overlaps(start, end, block_start, block_end))
- continue;
-
- if (drm_buddy_block_is_allocated(block)) {
- err = -ENOSPC;
- goto err_free;
- }
-
- if (contains(start, end, block_start, block_end)) {
- if (drm_buddy_block_is_free(block)) {
- mark_allocated(mm, block);
- total_allocated += drm_buddy_block_size(mm, block);
- mm->avail -= drm_buddy_block_size(mm, block);
- if (drm_buddy_block_is_clear(block))
- mm->clear_avail -= drm_buddy_block_size(mm, block);
- list_add_tail(&block->link, &allocated);
- continue;
- } else if (!mm->clear_avail) {
- err = -ENOSPC;
- goto err_free;
- }
- }
-
- if (!drm_buddy_block_is_split(block)) {
- err = split_block(mm, block);
- if (unlikely(err))
- goto err_undo;
- }
-
- list_add(&block->right->tmp_link, dfs);
- list_add(&block->left->tmp_link, dfs);
- } while (1);
-
- if (total_allocated < size) {
- err = -ENOSPC;
- goto err_free;
- }
-
- list_splice_tail(&allocated, blocks);
-
- return 0;
-
-err_undo:
- /*
- * We really don't want to leave around a bunch of split blocks, since
- * bigger is better, so make sure we merge everything back before we
- * free the allocated blocks.
- */
- buddy = __get_buddy(block);
- if (buddy &&
- (drm_buddy_block_is_free(block) &&
- drm_buddy_block_is_free(buddy)))
- __drm_buddy_free(mm, block, false);
-
-err_free:
- if (err == -ENOSPC && total_allocated_on_err) {
- list_splice_tail(&allocated, blocks);
- *total_allocated_on_err = total_allocated;
- } else {
- drm_buddy_free_list_internal(mm, &allocated);
- }
-
- return err;
-}
-
-static int __drm_buddy_alloc_range(struct drm_buddy *mm,
- u64 start,
- u64 size,
- u64 *total_allocated_on_err,
- struct list_head *blocks)
-{
- LIST_HEAD(dfs);
- int i;
-
- for (i = 0; i < mm->n_roots; ++i)
- list_add_tail(&mm->roots[i]->tmp_link, &dfs);
-
- return __alloc_range(mm, &dfs, start, size,
- blocks, total_allocated_on_err);
-}
-
-static int __alloc_contig_try_harder(struct drm_buddy *mm,
- u64 size,
- u64 min_block_size,
- struct list_head *blocks)
-{
- u64 rhs_offset, lhs_offset, lhs_size, filled;
- struct drm_buddy_block *block;
- unsigned int tree, order;
- LIST_HEAD(blocks_lhs);
- unsigned long pages;
- u64 modify_size;
- int err;
-
- modify_size = rounddown_pow_of_two(size);
- pages = modify_size >> ilog2(mm->chunk_size);
- order = fls(pages) - 1;
- if (order == 0)
- return -ENOSPC;
-
- for_each_free_tree(tree) {
- struct rb_root *root;
- struct rb_node *iter;
-
- root = &mm->free_trees[tree][order];
- if (rbtree_is_empty(root))
- continue;
-
- iter = rb_last(root);
- while (iter) {
- block = rbtree_get_free_block(iter);
-
- /* Allocate blocks traversing RHS */
- rhs_offset = drm_buddy_block_offset(block);
- err = __drm_buddy_alloc_range(mm, rhs_offset, size,
- &filled, blocks);
- if (!err || err != -ENOSPC)
- return err;
-
- lhs_size = max((size - filled), min_block_size);
- if (!IS_ALIGNED(lhs_size, min_block_size))
- lhs_size = round_up(lhs_size, min_block_size);
-
- /* Allocate blocks traversing LHS */
- lhs_offset = drm_buddy_block_offset(block) - lhs_size;
- err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size,
- NULL, &blocks_lhs);
- if (!err) {
- list_splice(&blocks_lhs, blocks);
- return 0;
- } else if (err != -ENOSPC) {
- drm_buddy_free_list_internal(mm, blocks);
- return err;
- }
- /* Free blocks for the next iteration */
- drm_buddy_free_list_internal(mm, blocks);
-
- iter = rb_prev(iter);
- }
- }
-
- return -ENOSPC;
-}
-
-/**
- * drm_buddy_block_trim - free unused pages
- *
- * @mm: DRM buddy manager
- * @start: start address to begin the trimming.
- * @new_size: original size requested
- * @blocks: Input and output list of allocated blocks.
- * MUST contain single block as input to be trimmed.
- * On success will contain the newly allocated blocks
- * making up the @new_size. Blocks always appear in
- * ascending order
- *
- * For contiguous allocation, we round up the size to the nearest
- * power of two value, drivers consume *actual* size, so remaining
- * portions are unused and can be optionally freed with this function
- *
- * Returns:
- * 0 on success, error code on failure.
- */
-int drm_buddy_block_trim(struct drm_buddy *mm,
- u64 *start,
- u64 new_size,
- struct list_head *blocks)
-{
- struct drm_buddy_block *parent;
- struct drm_buddy_block *block;
- u64 block_start, block_end;
- LIST_HEAD(dfs);
- u64 new_start;
- int err;
-
- if (!list_is_singular(blocks))
- return -EINVAL;
-
- block = list_first_entry(blocks,
- struct drm_buddy_block,
- link);
-
- block_start = drm_buddy_block_offset(block);
- block_end = block_start + drm_buddy_block_size(mm, block);
-
- if (WARN_ON(!drm_buddy_block_is_allocated(block)))
- return -EINVAL;
-
- if (new_size > drm_buddy_block_size(mm, block))
- return -EINVAL;
-
- if (!new_size || !IS_ALIGNED(new_size, mm->chunk_size))
- return -EINVAL;
-
- if (new_size == drm_buddy_block_size(mm, block))
- return 0;
-
- new_start = block_start;
- if (start) {
- new_start = *start;
-
- if (new_start < block_start)
- return -EINVAL;
-
- if (!IS_ALIGNED(new_start, mm->chunk_size))
- return -EINVAL;
-
- if (range_overflows(new_start, new_size, block_end))
- return -EINVAL;
- }
-
- list_del(&block->link);
- mark_free(mm, block);
- mm->avail += drm_buddy_block_size(mm, block);
- if (drm_buddy_block_is_clear(block))
- mm->clear_avail += drm_buddy_block_size(mm, block);
-
- /* Prevent recursively freeing this node */
- parent = block->parent;
- block->parent = NULL;
-
- list_add(&block->tmp_link, &dfs);
- err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL);
- if (err) {
- mark_allocated(mm, block);
- mm->avail -= drm_buddy_block_size(mm, block);
- if (drm_buddy_block_is_clear(block))
- mm->clear_avail -= drm_buddy_block_size(mm, block);
- list_add(&block->link, blocks);
- }
-
- block->parent = parent;
- return err;
-}
-EXPORT_SYMBOL(drm_buddy_block_trim);
-
-static struct drm_buddy_block *
-__drm_buddy_alloc_blocks(struct drm_buddy *mm,
- u64 start, u64 end,
- unsigned int order,
- unsigned long flags)
-{
- if (flags & DRM_BUDDY_RANGE_ALLOCATION)
- /* Allocate traversing within the range */
- return __drm_buddy_alloc_range_bias(mm, start, end,
- order, flags);
- else
- /* Allocate from freetree */
- return alloc_from_freetree(mm, order, flags);
-}
-
-/**
- * drm_buddy_alloc_blocks - allocate power-of-two blocks
- *
- * @mm: DRM buddy manager to allocate from
- * @start: start of the allowed range for this block
- * @end: end of the allowed range for this block
- * @size: size of the allocation in bytes
- * @min_block_size: alignment of the allocation
- * @blocks: output list head to add allocated blocks
- * @flags: DRM_BUDDY_*_ALLOCATION flags
- *
- * alloc_range_bias() called on range limitations, which traverses
- * the tree and returns the desired block.
- *
- * alloc_from_freetree() called when *no* range restrictions
- * are enforced, which picks the block from the freetree.
- *
- * Returns:
- * 0 on success, error code on failure.
- */
-int drm_buddy_alloc_blocks(struct drm_buddy *mm,
- u64 start, u64 end, u64 size,
- u64 min_block_size,
- struct list_head *blocks,
- unsigned long flags)
-{
- struct drm_buddy_block *block = NULL;
- u64 original_size, original_min_size;
- unsigned int min_order, order;
- LIST_HEAD(allocated);
- unsigned long pages;
- int err;
-
- if (size < mm->chunk_size)
- return -EINVAL;
-
- if (min_block_size < mm->chunk_size)
- return -EINVAL;
-
- if (!is_power_of_2(min_block_size))
- return -EINVAL;
-
- if (!IS_ALIGNED(start | end | size, mm->chunk_size))
- return -EINVAL;
-
- if (end > mm->size)
- return -EINVAL;
-
- if (range_overflows(start, size, mm->size))
- return -EINVAL;
-
- /* Actual range allocation */
- if (start + size == end) {
- if (!IS_ALIGNED(start | end, min_block_size))
- return -EINVAL;
-
- return __drm_buddy_alloc_range(mm, start, size, NULL, blocks);
- }
-
- original_size = size;
- original_min_size = min_block_size;
-
- /* Roundup the size to power of 2 */
- if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION) {
- size = roundup_pow_of_two(size);
- min_block_size = size;
- /* Align size value to min_block_size */
- } else if (!IS_ALIGNED(size, min_block_size)) {
- size = round_up(size, min_block_size);
- }
-
- pages = size >> ilog2(mm->chunk_size);
- order = fls(pages) - 1;
- min_order = ilog2(min_block_size) - ilog2(mm->chunk_size);
-
- if (order > mm->max_order || size > mm->size) {
- if ((flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION) &&
- !(flags & DRM_BUDDY_RANGE_ALLOCATION))
- return __alloc_contig_try_harder(mm, original_size,
- original_min_size, blocks);
-
- return -EINVAL;
- }
-
- do {
- order = min(order, (unsigned int)fls(pages) - 1);
- BUG_ON(order > mm->max_order);
- BUG_ON(order < min_order);
-
- do {
- block = __drm_buddy_alloc_blocks(mm, start,
- end,
- order,
- flags);
- if (!IS_ERR(block))
- break;
-
- if (order-- == min_order) {
- /* Try allocation through force merge method */
- if (mm->clear_avail &&
- !__force_merge(mm, start, end, min_order)) {
- block = __drm_buddy_alloc_blocks(mm, start,
- end,
- min_order,
- flags);
- if (!IS_ERR(block)) {
- order = min_order;
- break;
- }
- }
-
- /*
- * Try contiguous block allocation through
- * try harder method.
- */
- if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION &&
- !(flags & DRM_BUDDY_RANGE_ALLOCATION))
- return __alloc_contig_try_harder(mm,
- original_size,
- original_min_size,
- blocks);
- err = -ENOSPC;
- goto err_free;
- }
- } while (1);
-
- mark_allocated(mm, block);
- mm->avail -= drm_buddy_block_size(mm, block);
- if (drm_buddy_block_is_clear(block))
- mm->clear_avail -= drm_buddy_block_size(mm, block);
- kmemleak_update_trace(block);
- list_add_tail(&block->link, &allocated);
-
- pages -= BIT(order);
-
- if (!pages)
- break;
- } while (1);
-
- /* Trim the allocated block to the required size */
- if (!(flags & DRM_BUDDY_TRIM_DISABLE) &&
- original_size != size) {
- struct list_head *trim_list;
- LIST_HEAD(temp);
- u64 trim_size;
-
- trim_list = &allocated;
- trim_size = original_size;
-
- if (!list_is_singular(&allocated)) {
- block = list_last_entry(&allocated, typeof(*block), link);
- list_move(&block->link, &temp);
- trim_list = &temp;
- trim_size = drm_buddy_block_size(mm, block) -
- (size - original_size);
- }
-
- drm_buddy_block_trim(mm,
- NULL,
- trim_size,
- trim_list);
-
- if (!list_empty(&temp))
- list_splice_tail(trim_list, &allocated);
- }
-
- list_splice_tail(&allocated, blocks);
- return 0;
-
-err_free:
- drm_buddy_free_list_internal(mm, &allocated);
- return err;
-}
-EXPORT_SYMBOL(drm_buddy_alloc_blocks);
+#include <drm/drm_print.h>
/**
* drm_buddy_block_print - print block information
@@ -1257,12 +21,12 @@ EXPORT_SYMBOL(drm_buddy_alloc_blocks);
* @block: DRM buddy block
* @p: DRM printer to use
*/
-void drm_buddy_block_print(struct drm_buddy *mm,
- struct drm_buddy_block *block,
+void drm_buddy_block_print(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block,
struct drm_printer *p)
{
- u64 start = drm_buddy_block_offset(block);
- u64 size = drm_buddy_block_size(mm, block);
+ u64 start = gpu_buddy_block_offset(block);
+ u64 size = gpu_buddy_block_size(mm, block);
drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size);
}
@@ -1274,7 +38,7 @@ EXPORT_SYMBOL(drm_buddy_block_print);
* @mm: DRM buddy manager
* @p: DRM printer to use
*/
-void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p)
+void drm_buddy_print(struct gpu_buddy *mm, struct drm_printer *p)
{
int order;
@@ -1282,7 +46,7 @@ void drm_buddy_print(struct drm_buddy *m
mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20);
for (order = mm->max_order; order >= 0; order--) {
- struct drm_buddy_block *block, *tmp;
+ struct gpu_buddy_block *block, *tmp;
struct rb_root *root;
u64 count = 0, free;
unsigned int tree;
@@ -1291,7 +55,7 @@ void drm_buddy_print(struct drm_buddy *m
root = &mm->free_trees[tree][order];
rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) {
- BUG_ON(!drm_buddy_block_is_free(block));
+ BUG_ON(!gpu_buddy_block_is_free(block));
count++;
}
}
@@ -1309,22 +73,5 @@ void drm_buddy_print(struct drm_buddy *m
}
EXPORT_SYMBOL(drm_buddy_print);
-static void drm_buddy_module_exit(void)
-{
- kmem_cache_destroy(slab_blocks);
-}
-
-static int __init drm_buddy_module_init(void)
-{
- slab_blocks = KMEM_CACHE(drm_buddy_block, 0);
- if (!slab_blocks)
- return -ENOMEM;
-
- return 0;
-}
-
-module_init(drm_buddy_module_init);
-module_exit(drm_buddy_module_exit);
-
-MODULE_DESCRIPTION("DRM Buddy Allocator");
+MODULE_DESCRIPTION("DRM-specific GPU Buddy Allocator Print Helpers");
MODULE_LICENSE("Dual MIT/GPL");
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -7,7 +7,7 @@
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_tt.h>
-#include <drm/drm_buddy.h>
+#include <linux/gpu_buddy.h>
#include "i915_drv.h"
#include "i915_ttm_buddy_manager.h"
--- a/drivers/gpu/drm/i915/i915_scatterlist.c
+++ b/drivers/gpu/drm/i915/i915_scatterlist.c
@@ -7,7 +7,7 @@
#include "i915_scatterlist.h"
#include "i915_ttm_buddy_manager.h"
-#include <drm/drm_buddy.h>
+#include <linux/gpu_buddy.h>
#include <drm/drm_mm.h>
#include <linux/slab.h>
@@ -167,9 +167,9 @@ struct i915_refct_sgt *i915_rsgt_from_bu
struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
const u64 size = res->size;
const u32 max_segment = round_down(UINT_MAX, page_alignment);
- struct drm_buddy *mm = bman_res->mm;
+ struct gpu_buddy *mm = bman_res->mm;
struct list_head *blocks = &bman_res->blocks;
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
struct i915_refct_sgt *rsgt;
struct scatterlist *sg;
struct sg_table *st;
@@ -202,8 +202,8 @@ struct i915_refct_sgt *i915_rsgt_from_bu
list_for_each_entry(block, blocks, link) {
u64 block_size, offset;
- block_size = min_t(u64, size, drm_buddy_block_size(mm, block));
- offset = drm_buddy_block_offset(block);
+ block_size = min_t(u64, size, gpu_buddy_block_size(mm, block));
+ offset = gpu_buddy_block_offset(block);
while (block_size) {
u64 len;
--- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
+++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
@@ -8,6 +8,7 @@
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_bo.h>
+#include <linux/gpu_buddy.h>
#include <drm/drm_buddy.h>
#include "i915_ttm_buddy_manager.h"
@@ -16,7 +17,7 @@
struct i915_ttm_buddy_manager {
struct ttm_resource_manager manager;
- struct drm_buddy mm;
+ struct gpu_buddy mm;
struct list_head reserved;
struct mutex lock;
unsigned long visible_size;
@@ -38,7 +39,7 @@ static int i915_ttm_buddy_man_alloc(stru
{
struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
struct i915_ttm_buddy_resource *bman_res;
- struct drm_buddy *mm = &bman->mm;
+ struct gpu_buddy *mm = &bman->mm;
unsigned long n_pages, lpfn;
u64 min_page_size;
u64 size;
@@ -57,13 +58,13 @@ static int i915_ttm_buddy_man_alloc(stru
bman_res->mm = mm;
if (place->flags & TTM_PL_FLAG_TOPDOWN)
- bman_res->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
+ bman_res->flags |= GPU_BUDDY_TOPDOWN_ALLOCATION;
if (place->flags & TTM_PL_FLAG_CONTIGUOUS)
- bman_res->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION;
+ bman_res->flags |= GPU_BUDDY_CONTIGUOUS_ALLOCATION;
if (place->fpfn || lpfn != man->size)
- bman_res->flags |= DRM_BUDDY_RANGE_ALLOCATION;
+ bman_res->flags |= GPU_BUDDY_RANGE_ALLOCATION;
GEM_BUG_ON(!bman_res->base.size);
size = bman_res->base.size;
@@ -89,7 +90,7 @@ static int i915_ttm_buddy_man_alloc(stru
goto err_free_res;
}
- err = drm_buddy_alloc_blocks(mm, (u64)place->fpfn << PAGE_SHIFT,
+ err = gpu_buddy_alloc_blocks(mm, (u64)place->fpfn << PAGE_SHIFT,
(u64)lpfn << PAGE_SHIFT,
(u64)n_pages << PAGE_SHIFT,
min_page_size,
@@ -101,15 +102,15 @@ static int i915_ttm_buddy_man_alloc(stru
if (lpfn <= bman->visible_size) {
bman_res->used_visible_size = PFN_UP(bman_res->base.size);
} else {
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
list_for_each_entry(block, &bman_res->blocks, link) {
unsigned long start =
- drm_buddy_block_offset(block) >> PAGE_SHIFT;
+ gpu_buddy_block_offset(block) >> PAGE_SHIFT;
if (start < bman->visible_size) {
unsigned long end = start +
- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT);
+ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT);
bman_res->used_visible_size +=
min(end, bman->visible_size) - start;
@@ -126,7 +127,7 @@ static int i915_ttm_buddy_man_alloc(stru
return 0;
err_free_blocks:
- drm_buddy_free_list(mm, &bman_res->blocks, 0);
+ gpu_buddy_free_list(mm, &bman_res->blocks, 0);
mutex_unlock(&bman->lock);
err_free_res:
ttm_resource_fini(man, &bman_res->base);
@@ -141,7 +142,7 @@ static void i915_ttm_buddy_man_free(stru
struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
mutex_lock(&bman->lock);
- drm_buddy_free_list(&bman->mm, &bman_res->blocks, 0);
+ gpu_buddy_free_list(&bman->mm, &bman_res->blocks, 0);
bman->visible_avail += bman_res->used_visible_size;
mutex_unlock(&bman->lock);
@@ -156,8 +157,8 @@ static bool i915_ttm_buddy_man_intersect
{
struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
- struct drm_buddy *mm = &bman->mm;
- struct drm_buddy_block *block;
+ struct gpu_buddy *mm = &bman->mm;
+ struct gpu_buddy_block *block;
if (!place->fpfn && !place->lpfn)
return true;
@@ -176,9 +177,9 @@ static bool i915_ttm_buddy_man_intersect
/* Check each drm buddy block individually */
list_for_each_entry(block, &bman_res->blocks, link) {
unsigned long fpfn =
- drm_buddy_block_offset(block) >> PAGE_SHIFT;
+ gpu_buddy_block_offset(block) >> PAGE_SHIFT;
unsigned long lpfn = fpfn +
- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT);
+ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT);
if (place->fpfn < lpfn && place->lpfn > fpfn)
return true;
@@ -194,8 +195,8 @@ static bool i915_ttm_buddy_man_compatibl
{
struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
- struct drm_buddy *mm = &bman->mm;
- struct drm_buddy_block *block;
+ struct gpu_buddy *mm = &bman->mm;
+ struct gpu_buddy_block *block;
if (!place->fpfn && !place->lpfn)
return true;
@@ -209,9 +210,9 @@ static bool i915_ttm_buddy_man_compatibl
/* Check each drm buddy block individually */
list_for_each_entry(block, &bman_res->blocks, link) {
unsigned long fpfn =
- drm_buddy_block_offset(block) >> PAGE_SHIFT;
+ gpu_buddy_block_offset(block) >> PAGE_SHIFT;
unsigned long lpfn = fpfn +
- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT);
+ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT);
if (fpfn < place->fpfn || lpfn > place->lpfn)
return false;
@@ -224,7 +225,7 @@ static void i915_ttm_buddy_man_debug(str
struct drm_printer *printer)
{
struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
mutex_lock(&bman->lock);
drm_printf(printer, "default_page_size: %lluKiB\n",
@@ -293,7 +294,7 @@ int i915_ttm_buddy_man_init(struct ttm_d
if (!bman)
return -ENOMEM;
- err = drm_buddy_init(&bman->mm, size, chunk_size);
+ err = gpu_buddy_init(&bman->mm, size, chunk_size);
if (err)
goto err_free_bman;
@@ -333,7 +334,7 @@ int i915_ttm_buddy_man_fini(struct ttm_d
{
struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
- struct drm_buddy *mm = &bman->mm;
+ struct gpu_buddy *mm = &bman->mm;
int ret;
ttm_resource_manager_set_used(man, false);
@@ -345,8 +346,8 @@ int i915_ttm_buddy_man_fini(struct ttm_d
ttm_set_driver_manager(bdev, type, NULL);
mutex_lock(&bman->lock);
- drm_buddy_free_list(mm, &bman->reserved, 0);
- drm_buddy_fini(mm);
+ gpu_buddy_free_list(mm, &bman->reserved, 0);
+ gpu_buddy_fini(mm);
bman->visible_avail += bman->visible_reserved;
WARN_ON_ONCE(bman->visible_avail != bman->visible_size);
mutex_unlock(&bman->lock);
@@ -371,15 +372,15 @@ int i915_ttm_buddy_man_reserve(struct tt
u64 start, u64 size)
{
struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
- struct drm_buddy *mm = &bman->mm;
+ struct gpu_buddy *mm = &bman->mm;
unsigned long fpfn = start >> PAGE_SHIFT;
unsigned long flags = 0;
int ret;
- flags |= DRM_BUDDY_RANGE_ALLOCATION;
+ flags |= GPU_BUDDY_RANGE_ALLOCATION;
mutex_lock(&bman->lock);
- ret = drm_buddy_alloc_blocks(mm, start,
+ ret = gpu_buddy_alloc_blocks(mm, start,
start + size,
size, mm->chunk_size,
&bman->reserved,
--- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h
+++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h
@@ -13,7 +13,7 @@
struct ttm_device;
struct ttm_resource_manager;
-struct drm_buddy;
+struct gpu_buddy;
/**
* struct i915_ttm_buddy_resource
@@ -33,7 +33,7 @@ struct i915_ttm_buddy_resource {
struct list_head blocks;
unsigned long flags;
unsigned long used_visible_size;
- struct drm_buddy *mm;
+ struct gpu_buddy *mm;
};
/**
--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c
@@ -6,7 +6,7 @@
#include <linux/prime_numbers.h>
#include <linux/sort.h>
-#include <drm/drm_buddy.h>
+#include <linux/gpu_buddy.h>
#include "../i915_selftest.h"
@@ -371,7 +371,7 @@ static int igt_mock_splintered_region(vo
struct drm_i915_private *i915 = mem->i915;
struct i915_ttm_buddy_resource *res;
struct drm_i915_gem_object *obj;
- struct drm_buddy *mm;
+ struct gpu_buddy *mm;
unsigned int expected_order;
LIST_HEAD(objects);
u64 size;
@@ -455,8 +455,8 @@ static int igt_mock_max_segment(void *ar
struct drm_i915_private *i915 = mem->i915;
struct i915_ttm_buddy_resource *res;
struct drm_i915_gem_object *obj;
- struct drm_buddy_block *block;
- struct drm_buddy *mm;
+ struct gpu_buddy_block *block;
+ struct gpu_buddy *mm;
struct list_head *blocks;
struct scatterlist *sg;
I915_RND_STATE(prng);
@@ -495,8 +495,8 @@ static int igt_mock_max_segment(void *ar
mm = res->mm;
size = 0;
list_for_each_entry(block, blocks, link) {
- if (drm_buddy_block_size(mm, block) > size)
- size = drm_buddy_block_size(mm, block);
+ if (gpu_buddy_block_size(mm, block) > size)
+ size = gpu_buddy_block_size(mm, block);
}
if (size < max_segment) {
pr_err("%s: Failed to create a huge contiguous block [> %u], largest block %lld\n",
@@ -535,14 +535,14 @@ static u64 igt_object_mappable_total(str
struct intel_memory_region *mr = obj->mm.region;
struct i915_ttm_buddy_resource *bman_res =
to_ttm_buddy_resource(obj->mm.res);
- struct drm_buddy *mm = bman_res->mm;
- struct drm_buddy_block *block;
+ struct gpu_buddy *mm = bman_res->mm;
+ struct gpu_buddy_block *block;
u64 total;
total = 0;
list_for_each_entry(block, &bman_res->blocks, link) {
- u64 start = drm_buddy_block_offset(block);
- u64 end = start + drm_buddy_block_size(mm, block);
+ u64 start = gpu_buddy_block_offset(block);
+ u64 end = start + gpu_buddy_block_size(mm, block);
if (start < resource_size(&mr->io))
total += min_t(u64, end, resource_size(&mr->io)) - start;
--- a/drivers/gpu/drm/lib/drm_random.c
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include "drm_random.h"
-
-u32 drm_prandom_u32_max_state(u32 ep_ro, struct rnd_state *state)
-{
- return upper_32_bits((u64)prandom_u32_state(state) * ep_ro);
-}
-EXPORT_SYMBOL(drm_prandom_u32_max_state);
-
-void drm_random_reorder(unsigned int *order, unsigned int count,
- struct rnd_state *state)
-{
- unsigned int i, j;
-
- for (i = 0; i < count; ++i) {
- BUILD_BUG_ON(sizeof(unsigned int) > sizeof(u32));
- j = drm_prandom_u32_max_state(count, state);
- swap(order[i], order[j]);
- }
-}
-EXPORT_SYMBOL(drm_random_reorder);
-
-unsigned int *drm_random_order(unsigned int count, struct rnd_state *state)
-{
- unsigned int *order, i;
-
- order = kmalloc_array(count, sizeof(*order), GFP_KERNEL);
- if (!order)
- return order;
-
- for (i = 0; i < count; i++)
- order[i] = i;
-
- drm_random_reorder(order, count, state);
- return order;
-}
-EXPORT_SYMBOL(drm_random_order);
--- a/drivers/gpu/drm/lib/drm_random.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __DRM_RANDOM_H__
-#define __DRM_RANDOM_H__
-
-/* This is a temporary home for a couple of utility functions that should
- * be transposed to lib/ at the earliest convenience.
- */
-
-#include <linux/random.h>
-
-#define DRM_RND_STATE_INITIALIZER(seed__) ({ \
- struct rnd_state state__; \
- prandom_seed_state(&state__, (seed__)); \
- state__; \
-})
-
-#define DRM_RND_STATE(name__, seed__) \
- struct rnd_state name__ = DRM_RND_STATE_INITIALIZER(seed__)
-
-unsigned int *drm_random_order(unsigned int count,
- struct rnd_state *state);
-void drm_random_reorder(unsigned int *order,
- unsigned int count,
- struct rnd_state *state);
-u32 drm_prandom_u32_max_state(u32 ep_ro,
- struct rnd_state *state);
-
-#endif /* !__DRM_RANDOM_H__ */
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -4,7 +4,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) +=
drm_kunit_helpers.o
obj-$(CONFIG_DRM_KUNIT_TEST) += \
- drm_buddy_test.o \
drm_cmdline_parser_test.o \
drm_connector_test.o \
drm_damage_helper_test.o \
--- a/drivers/gpu/drm/tests/drm_buddy_test.c
+++ /dev/null
@@ -1,778 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2019 Intel Corporation
- * Copyright © 2022 Maíra Canal <mairacanal@riseup.net>
- */
-
-#include <kunit/test.h>
-
-#include <linux/prime_numbers.h>
-#include <linux/sched/signal.h>
-#include <linux/sizes.h>
-
-#include <drm/drm_buddy.h>
-
-#include "../lib/drm_random.h"
-
-static unsigned int random_seed;
-
-static inline u64 get_size(int order, u64 chunk_size)
-{
- return (1 << order) * chunk_size;
-}
-
-static void drm_test_buddy_alloc_range_bias(struct kunit *test)
-{
- u32 mm_size, size, ps, bias_size, bias_start, bias_end, bias_rem;
- DRM_RND_STATE(prng, random_seed);
- unsigned int i, count, *order;
- struct drm_buddy_block *block;
- unsigned long flags;
- struct drm_buddy mm;
- LIST_HEAD(allocated);
-
- bias_size = SZ_1M;
- ps = roundup_pow_of_two(prandom_u32_state(&prng) % bias_size);
- ps = max(SZ_4K, ps);
- mm_size = (SZ_8M-1) & ~(ps-1); /* Multiple roots */
-
- kunit_info(test, "mm_size=%u, ps=%u\n", mm_size, ps);
-
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps),
- "buddy_init failed\n");
-
- count = mm_size / bias_size;
- order = drm_random_order(count, &prng);
- KUNIT_EXPECT_TRUE(test, order);
-
- /*
- * Idea is to split the address space into uniform bias ranges, and then
- * in some random order allocate within each bias, using various
- * patterns within. This should detect if allocations leak out from a
- * given bias, for example.
- */
-
- for (i = 0; i < count; i++) {
- LIST_HEAD(tmp);
- u32 size;
-
- bias_start = order[i] * bias_size;
- bias_end = bias_start + bias_size;
- bias_rem = bias_size;
-
- /* internal round_up too big */
- KUNIT_ASSERT_TRUE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, bias_size + ps, bias_size,
- &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, bias_size, bias_size);
-
- /* size too big */
- KUNIT_ASSERT_TRUE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, bias_size + ps, ps,
- &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, bias_size + ps, ps);
-
- /* bias range too small for size */
- KUNIT_ASSERT_TRUE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start + ps,
- bias_end, bias_size, ps,
- &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
- bias_start + ps, bias_end, bias_size, ps);
-
- /* bias misaligned */
- KUNIT_ASSERT_TRUE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start + ps,
- bias_end - ps,
- bias_size >> 1, bias_size >> 1,
- &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc h didn't fail with bias(%x-%x), size=%u, ps=%u\n",
- bias_start + ps, bias_end - ps, bias_size >> 1, bias_size >> 1);
-
- /* single big page */
- KUNIT_ASSERT_FALSE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, bias_size, bias_size,
- &tmp,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, bias_size, bias_size);
- drm_buddy_free_list(&mm, &tmp, 0);
-
- /* single page with internal round_up */
- KUNIT_ASSERT_FALSE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, ps, bias_size,
- &tmp,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, ps, bias_size);
- drm_buddy_free_list(&mm, &tmp, 0);
-
- /* random size within */
- size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
- if (size)
- KUNIT_ASSERT_FALSE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, size, ps,
- &tmp,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, size, ps);
-
- bias_rem -= size;
- /* too big for current avail */
- KUNIT_ASSERT_TRUE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, bias_rem + ps, ps,
- &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, bias_rem + ps, ps);
-
- if (bias_rem) {
- /* random fill of the remainder */
- size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
- size = max(size, ps);
-
- KUNIT_ASSERT_FALSE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, size, ps,
- &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, size, ps);
- /*
- * Intentionally allow some space to be left
- * unallocated, and ideally not always on the bias
- * boundaries.
- */
- drm_buddy_free_list(&mm, &tmp, 0);
- } else {
- list_splice_tail(&tmp, &allocated);
- }
- }
-
- kfree(order);
- drm_buddy_free_list(&mm, &allocated, 0);
- drm_buddy_fini(&mm);
-
- /*
- * Something more free-form. Idea is to pick a random starting bias
- * range within the address space and then start filling it up. Also
- * randomly grow the bias range in both directions as we go along. This
- * should give us bias start/end which is not always uniform like above,
- * and in some cases will require the allocator to jump over already
- * allocated nodes in the middle of the address space.
- */
-
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps),
- "buddy_init failed\n");
-
- bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps);
- bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps);
- bias_end = max(bias_end, bias_start + ps);
- bias_rem = bias_end - bias_start;
-
- do {
- u32 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
-
- KUNIT_ASSERT_FALSE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, size, ps,
- &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, size, ps);
- bias_rem -= size;
-
- /*
- * Try to randomly grow the bias range in both directions, or
- * only one, or perhaps don't grow at all.
- */
- do {
- u32 old_bias_start = bias_start;
- u32 old_bias_end = bias_end;
-
- if (bias_start)
- bias_start -= round_up(prandom_u32_state(&prng) % bias_start, ps);
- if (bias_end != mm_size)
- bias_end += round_up(prandom_u32_state(&prng) % (mm_size - bias_end), ps);
-
- bias_rem += old_bias_start - bias_start;
- bias_rem += bias_end - old_bias_end;
- } while (!bias_rem && (bias_start || bias_end != mm_size));
- } while (bias_rem);
-
- KUNIT_ASSERT_EQ(test, bias_start, 0);
- KUNIT_ASSERT_EQ(test, bias_end, mm_size);
- KUNIT_ASSERT_TRUE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start, bias_end,
- ps, ps,
- &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc passed with bias(%x-%x), size=%u\n",
- bias_start, bias_end, ps);
-
- drm_buddy_free_list(&mm, &allocated, 0);
- drm_buddy_fini(&mm);
-
- /*
- * Allocate cleared blocks in the bias range when the DRM buddy's clear avail is
- * zero. This will validate the bias range allocation in scenarios like system boot
- * when no cleared blocks are available and exercise the fallback path too. The resulting
- * blocks should always be dirty.
- */
-
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps),
- "buddy_init failed\n");
-
- bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps);
- bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps);
- bias_end = max(bias_end, bias_start + ps);
- bias_rem = bias_end - bias_start;
-
- flags = DRM_BUDDY_CLEAR_ALLOCATION | DRM_BUDDY_RANGE_ALLOCATION;
- size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
-
- KUNIT_ASSERT_FALSE_MSG(test,
- drm_buddy_alloc_blocks(&mm, bias_start,
- bias_end, size, ps,
- &allocated,
- flags),
- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
- bias_start, bias_end, size, ps);
-
- list_for_each_entry(block, &allocated, link)
- KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false);
-
- drm_buddy_free_list(&mm, &allocated, 0);
- drm_buddy_fini(&mm);
-}
-
-static void drm_test_buddy_alloc_clear(struct kunit *test)
-{
- unsigned long n_pages, total, i = 0;
- DRM_RND_STATE(prng, random_seed);
- const unsigned long ps = SZ_4K;
- struct drm_buddy_block *block;
- const int max_order = 12;
- LIST_HEAD(allocated);
- struct drm_buddy mm;
- unsigned int order;
- u32 mm_size, size;
- LIST_HEAD(dirty);
- LIST_HEAD(clean);
-
- mm_size = SZ_4K << max_order;
- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
-
- KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
-
- /*
- * Idea is to allocate and free some random portion of the address space,
- * returning those pages as non-dirty and randomly alternate between
- * requesting dirty and non-dirty pages (not going over the limit
- * we freed as non-dirty), putting that into two separate lists.
- * Loop over both lists at the end checking that the dirty list
- * is indeed all dirty pages and vice versa. Free it all again,
- * keeping the dirty/clear status.
- */
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- 5 * ps, ps, &allocated,
- DRM_BUDDY_TOPDOWN_ALLOCATION),
- "buddy_alloc hit an error size=%lu\n", 5 * ps);
- drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED);
-
- n_pages = 10;
- do {
- unsigned long flags;
- struct list_head *list;
- int slot = i % 2;
-
- if (slot == 0) {
- list = &dirty;
- flags = 0;
- } else {
- list = &clean;
- flags = DRM_BUDDY_CLEAR_ALLOCATION;
- }
-
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- ps, ps, list,
- flags),
- "buddy_alloc hit an error size=%lu\n", ps);
- } while (++i < n_pages);
-
- list_for_each_entry(block, &clean, link)
- KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), true);
-
- list_for_each_entry(block, &dirty, link)
- KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false);
-
- drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED);
-
- /*
- * Trying to go over the clear limit for some allocation.
- * The allocation should never fail with reasonable page-size.
- */
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- 10 * ps, ps, &clean,
- DRM_BUDDY_CLEAR_ALLOCATION),
- "buddy_alloc hit an error size=%lu\n", 10 * ps);
-
- drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED);
- drm_buddy_free_list(&mm, &dirty, 0);
- drm_buddy_fini(&mm);
-
- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
-
- /*
- * Create a new mm. Intentionally fragment the address space by creating
- * two alternating lists. Free both lists, one as dirty the other as clean.
- * Try to allocate double the previous size with matching min_page_size. The
- * allocation should never fail as it calls the force_merge. Also check that
- * the page is always dirty after force_merge. Free the page as dirty, then
- * repeat the whole thing, increment the order until we hit the max_order.
- */
-
- i = 0;
- n_pages = mm_size / ps;
- do {
- struct list_head *list;
- int slot = i % 2;
-
- if (slot == 0)
- list = &dirty;
- else
- list = &clean;
-
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- ps, ps, list, 0),
- "buddy_alloc hit an error size=%lu\n", ps);
- } while (++i < n_pages);
-
- drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED);
- drm_buddy_free_list(&mm, &dirty, 0);
-
- order = 1;
- do {
- size = SZ_4K << order;
-
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- size, size, &allocated,
- DRM_BUDDY_CLEAR_ALLOCATION),
- "buddy_alloc hit an error size=%u\n", size);
- total = 0;
- list_for_each_entry(block, &allocated, link) {
- if (size != mm_size)
- KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false);
- total += drm_buddy_block_size(&mm, block);
- }
- KUNIT_EXPECT_EQ(test, total, size);
-
- drm_buddy_free_list(&mm, &allocated, 0);
- } while (++order <= max_order);
-
- drm_buddy_fini(&mm);
-
- /*
- * Create a new mm with a non power-of-two size. Allocate a random size, free as
- * cleared and then call fini. This will ensure the multi-root force merge during
- * fini.
- */
- mm_size = 12 * SZ_4K;
- size = max(round_up(prandom_u32_state(&prng) % mm_size, ps), ps);
- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- size, ps, &allocated,
- DRM_BUDDY_TOPDOWN_ALLOCATION),
- "buddy_alloc hit an error size=%u\n", size);
- drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED);
- drm_buddy_fini(&mm);
-}
-
-static void drm_test_buddy_alloc_contiguous(struct kunit *test)
-{
- const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K;
- unsigned long i, n_pages, total;
- struct drm_buddy_block *block;
- struct drm_buddy mm;
- LIST_HEAD(left);
- LIST_HEAD(middle);
- LIST_HEAD(right);
- LIST_HEAD(allocated);
-
- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
-
- /*
- * Idea is to fragment the address space by alternating block
- * allocations between three different lists; one for left, middle and
- * right. We can then free a list to simulate fragmentation. In
- * particular we want to exercise the DRM_BUDDY_CONTIGUOUS_ALLOCATION,
- * including the try_harder path.
- */
-
- i = 0;
- n_pages = mm_size / ps;
- do {
- struct list_head *list;
- int slot = i % 3;
-
- if (slot == 0)
- list = &left;
- else if (slot == 1)
- list = &middle;
- else
- list = &right;
- KUNIT_ASSERT_FALSE_MSG(test,
- drm_buddy_alloc_blocks(&mm, 0, mm_size,
- ps, ps, list, 0),
- "buddy_alloc hit an error size=%lu\n",
- ps);
- } while (++i < n_pages);
-
- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- 3 * ps, ps, &allocated,
- DRM_BUDDY_CONTIGUOUS_ALLOCATION),
- "buddy_alloc didn't error size=%lu\n", 3 * ps);
-
- drm_buddy_free_list(&mm, &middle, 0);
- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- 3 * ps, ps, &allocated,
- DRM_BUDDY_CONTIGUOUS_ALLOCATION),
- "buddy_alloc didn't error size=%lu\n", 3 * ps);
- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- 2 * ps, ps, &allocated,
- DRM_BUDDY_CONTIGUOUS_ALLOCATION),
- "buddy_alloc didn't error size=%lu\n", 2 * ps);
-
- drm_buddy_free_list(&mm, &right, 0);
- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- 3 * ps, ps, &allocated,
- DRM_BUDDY_CONTIGUOUS_ALLOCATION),
- "buddy_alloc didn't error size=%lu\n", 3 * ps);
- /*
- * At this point we should have enough contiguous space for 2 blocks,
- * however they are never buddies (since we freed middle and right) so
- * will require the try_harder logic to find them.
- */
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- 2 * ps, ps, &allocated,
- DRM_BUDDY_CONTIGUOUS_ALLOCATION),
- "buddy_alloc hit an error size=%lu\n", 2 * ps);
-
- drm_buddy_free_list(&mm, &left, 0);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
- 3 * ps, ps, &allocated,
- DRM_BUDDY_CONTIGUOUS_ALLOCATION),
- "buddy_alloc hit an error size=%lu\n", 3 * ps);
-
- total = 0;
- list_for_each_entry(block, &allocated, link)
- total += drm_buddy_block_size(&mm, block);
-
- KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3);
-
- drm_buddy_free_list(&mm, &allocated, 0);
- drm_buddy_fini(&mm);
-}
-
-static void drm_test_buddy_alloc_pathological(struct kunit *test)
-{
- u64 mm_size, size, start = 0;
- struct drm_buddy_block *block;
- const int max_order = 3;
- unsigned long flags = 0;
- int order, top;
- struct drm_buddy mm;
- LIST_HEAD(blocks);
- LIST_HEAD(holes);
- LIST_HEAD(tmp);
-
- /*
- * Create a pot-sized mm, then allocate one of each possible
- * order within. This should leave the mm with exactly one
- * page left. Free the largest block, then whittle down again.
- * Eventually we will have a fully 50% fragmented mm.
- */
-
- mm_size = SZ_4K << max_order;
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, SZ_4K),
- "buddy_init failed\n");
-
- KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
-
- for (top = max_order; top; top--) {
- /* Make room by freeing the largest allocated block */
- block = list_first_entry_or_null(&blocks, typeof(*block), link);
- if (block) {
- list_del(&block->link);
- drm_buddy_free_block(&mm, block);
- }
-
- for (order = top; order--;) {
- size = get_size(order, mm.chunk_size);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start,
- mm_size, size, size,
- &tmp, flags),
- "buddy_alloc hit -ENOMEM with order=%d, top=%d\n",
- order, top);
-
- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link);
- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
-
- list_move_tail(&block->link, &blocks);
- }
-
- /* There should be one final page for this sub-allocation */
- size = get_size(0, mm.chunk_size);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc hit -ENOMEM for hole\n");
-
- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link);
- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
-
- list_move_tail(&block->link, &holes);
-
- size = get_size(top, mm.chunk_size);
- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!",
- top, max_order);
- }
-
- drm_buddy_free_list(&mm, &holes, 0);
-
- /* Nothing larger than blocks of chunk_size now available */
- for (order = 1; order <= max_order; order++) {
- size = get_size(order, mm.chunk_size);
- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc unexpectedly succeeded at order %d, it should be full!",
- order);
- }
-
- list_splice_tail(&holes, &blocks);
- drm_buddy_free_list(&mm, &blocks, 0);
- drm_buddy_fini(&mm);
-}
-
-static void drm_test_buddy_alloc_pessimistic(struct kunit *test)
-{
- u64 mm_size, size, start = 0;
- struct drm_buddy_block *block, *bn;
- const unsigned int max_order = 16;
- unsigned long flags = 0;
- struct drm_buddy mm;
- unsigned int order;
- LIST_HEAD(blocks);
- LIST_HEAD(tmp);
-
- /*
- * Create a pot-sized mm, then allocate one of each possible
- * order within. This should leave the mm with exactly one
- * page left.
- */
-
- mm_size = SZ_4K << max_order;
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, SZ_4K),
- "buddy_init failed\n");
-
- KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
-
- for (order = 0; order < max_order; order++) {
- size = get_size(order, mm.chunk_size);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc hit -ENOMEM with order=%d\n",
- order);
-
- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link);
- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
-
- list_move_tail(&block->link, &blocks);
- }
-
- /* And now the last remaining block available */
- size = get_size(0, mm.chunk_size);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc hit -ENOMEM on final alloc\n");
-
- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link);
- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
-
- list_move_tail(&block->link, &blocks);
-
- /* Should be completely full! */
- for (order = max_order; order--;) {
- size = get_size(order, mm.chunk_size);
- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc unexpectedly succeeded, it should be full!");
- }
-
- block = list_last_entry(&blocks, typeof(*block), link);
- list_del(&block->link);
- drm_buddy_free_block(&mm, block);
-
- /* As we free in increasing size, we make available larger blocks */
- order = 1;
- list_for_each_entry_safe(block, bn, &blocks, link) {
- list_del(&block->link);
- drm_buddy_free_block(&mm, block);
-
- size = get_size(order, mm.chunk_size);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc hit -ENOMEM with order=%d\n",
- order);
-
- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link);
- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
-
- list_del(&block->link);
- drm_buddy_free_block(&mm, block);
- order++;
- }
-
- /* To confirm, now the whole mm should be available */
- size = get_size(max_order, mm.chunk_size);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc (realloc) hit -ENOMEM with order=%d\n",
- max_order);
-
- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link);
- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
-
- list_del(&block->link);
- drm_buddy_free_block(&mm, block);
- drm_buddy_free_list(&mm, &blocks, 0);
- drm_buddy_fini(&mm);
-}
-
-static void drm_test_buddy_alloc_optimistic(struct kunit *test)
-{
- u64 mm_size, size, start = 0;
- struct drm_buddy_block *block;
- unsigned long flags = 0;
- const int max_order = 16;
- struct drm_buddy mm;
- LIST_HEAD(blocks);
- LIST_HEAD(tmp);
- int order;
-
- /*
- * Create a mm with one block of each order available, and
- * try to allocate them all.
- */
-
- mm_size = SZ_4K * ((1 << (max_order + 1)) - 1);
-
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, SZ_4K),
- "buddy_init failed\n");
-
- KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
-
- for (order = 0; order <= max_order; order++) {
- size = get_size(order, mm.chunk_size);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc hit -ENOMEM with order=%d\n",
- order);
-
- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link);
- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
-
- list_move_tail(&block->link, &blocks);
- }
-
- /* Should be completely full! */
- size = get_size(0, mm.chunk_size);
- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size,
- size, size, &tmp, flags),
- "buddy_alloc unexpectedly succeeded, it should be full!");
-
- drm_buddy_free_list(&mm, &blocks, 0);
- drm_buddy_fini(&mm);
-}
-
-static void drm_test_buddy_alloc_limit(struct kunit *test)
-{
- u64 size = U64_MAX, start = 0;
- struct drm_buddy_block *block;
- unsigned long flags = 0;
- LIST_HEAD(allocated);
- struct drm_buddy mm;
-
- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, size, SZ_4K));
-
- KUNIT_EXPECT_EQ_MSG(test, mm.max_order, DRM_BUDDY_MAX_ORDER,
- "mm.max_order(%d) != %d\n", mm.max_order,
- DRM_BUDDY_MAX_ORDER);
-
- size = mm.chunk_size << mm.max_order;
- KUNIT_EXPECT_FALSE(test, drm_buddy_alloc_blocks(&mm, start, size, size,
- mm.chunk_size, &allocated, flags));
-
- block = list_first_entry_or_null(&allocated, struct drm_buddy_block, link);
- KUNIT_EXPECT_TRUE(test, block);
-
- KUNIT_EXPECT_EQ_MSG(test, drm_buddy_block_order(block), mm.max_order,
- "block order(%d) != %d\n",
- drm_buddy_block_order(block), mm.max_order);
-
- KUNIT_EXPECT_EQ_MSG(test, drm_buddy_block_size(&mm, block),
- BIT_ULL(mm.max_order) * mm.chunk_size,
- "block size(%llu) != %llu\n",
- drm_buddy_block_size(&mm, block),
- BIT_ULL(mm.max_order) * mm.chunk_size);
-
- drm_buddy_free_list(&mm, &allocated, 0);
- drm_buddy_fini(&mm);
-}
-
-static int drm_buddy_suite_init(struct kunit_suite *suite)
-{
- while (!random_seed)
- random_seed = get_random_u32();
-
- kunit_info(suite, "Testing DRM buddy manager, with random_seed=0x%x\n",
- random_seed);
-
- return 0;
-}
-
-static struct kunit_case drm_buddy_tests[] = {
- KUNIT_CASE(drm_test_buddy_alloc_limit),
- KUNIT_CASE(drm_test_buddy_alloc_optimistic),
- KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
- KUNIT_CASE(drm_test_buddy_alloc_pathological),
- KUNIT_CASE(drm_test_buddy_alloc_contiguous),
- KUNIT_CASE(drm_test_buddy_alloc_clear),
- KUNIT_CASE(drm_test_buddy_alloc_range_bias),
- {}
-};
-
-static struct kunit_suite drm_buddy_test_suite = {
- .name = "drm_buddy",
- .suite_init = drm_buddy_suite_init,
- .test_cases = drm_buddy_tests,
-};
-
-kunit_test_suite(drm_buddy_test_suite);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("Kunit test for drm_buddy functions");
-MODULE_LICENSE("GPL");
--- a/drivers/gpu/drm/tests/drm_exec_test.c
+++ b/drivers/gpu/drm/tests/drm_exec_test.c
@@ -16,8 +16,6 @@
#include <drm/drm_gem.h>
#include <drm/drm_kunit_helpers.h>
-#include "../lib/drm_random.h"
-
struct drm_exec_priv {
struct device *dev;
struct drm_device *drm;
--- a/drivers/gpu/drm/tests/drm_mm_test.c
+++ b/drivers/gpu/drm/tests/drm_mm_test.c
@@ -15,8 +15,6 @@
#include <drm/drm_mm.h>
-#include "../lib/drm_random.h"
-
enum {
BEST,
BOTTOMUP,
--- a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c
+++ b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c
@@ -251,7 +251,7 @@ static void ttm_bo_validate_basic(struct
NULL, &dummy_ttm_bo_destroy);
KUNIT_EXPECT_EQ(test, err, 0);
- snd_place = ttm_place_kunit_init(test, snd_mem, DRM_BUDDY_TOPDOWN_ALLOCATION);
+ snd_place = ttm_place_kunit_init(test, snd_mem, GPU_BUDDY_TOPDOWN_ALLOCATION);
snd_placement = ttm_placement_kunit_init(test, snd_place, 1);
err = ttm_bo_validate(bo, snd_placement, &ctx_val);
@@ -263,7 +263,7 @@ static void ttm_bo_validate_basic(struct
KUNIT_EXPECT_TRUE(test, ttm_tt_is_populated(bo->ttm));
KUNIT_EXPECT_EQ(test, bo->resource->mem_type, snd_mem);
KUNIT_EXPECT_EQ(test, bo->resource->placement,
- DRM_BUDDY_TOPDOWN_ALLOCATION);
+ GPU_BUDDY_TOPDOWN_ALLOCATION);
ttm_bo_put(bo);
ttm_mock_manager_fini(priv->ttm_dev, snd_mem);
--- a/drivers/gpu/drm/ttm/tests/ttm_mock_manager.c
+++ b/drivers/gpu/drm/ttm/tests/ttm_mock_manager.c
@@ -27,7 +27,7 @@ static int ttm_mock_manager_alloc(struct
{
struct ttm_mock_manager *manager = to_mock_mgr(man);
struct ttm_mock_resource *mock_res;
- struct drm_buddy *mm = &manager->mm;
+ struct gpu_buddy *mm = &manager->mm;
u64 lpfn, fpfn, alloc_size;
int err;
@@ -43,14 +43,14 @@ static int ttm_mock_manager_alloc(struct
INIT_LIST_HEAD(&mock_res->blocks);
if (place->flags & TTM_PL_FLAG_TOPDOWN)
- mock_res->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
+ mock_res->flags |= GPU_BUDDY_TOPDOWN_ALLOCATION;
if (place->flags & TTM_PL_FLAG_CONTIGUOUS)
- mock_res->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION;
+ mock_res->flags |= GPU_BUDDY_CONTIGUOUS_ALLOCATION;
alloc_size = (uint64_t)mock_res->base.size;
mutex_lock(&manager->lock);
- err = drm_buddy_alloc_blocks(mm, fpfn, lpfn, alloc_size,
+ err = gpu_buddy_alloc_blocks(mm, fpfn, lpfn, alloc_size,
manager->default_page_size,
&mock_res->blocks,
mock_res->flags);
@@ -63,7 +63,7 @@ static int ttm_mock_manager_alloc(struct
return 0;
error_free_blocks:
- drm_buddy_free_list(mm, &mock_res->blocks, 0);
+ gpu_buddy_free_list(mm, &mock_res->blocks, 0);
ttm_resource_fini(man, &mock_res->base);
mutex_unlock(&manager->lock);
@@ -75,10 +75,10 @@ static void ttm_mock_manager_free(struct
{
struct ttm_mock_manager *manager = to_mock_mgr(man);
struct ttm_mock_resource *mock_res = to_mock_mgr_resource(res);
- struct drm_buddy *mm = &manager->mm;
+ struct gpu_buddy *mm = &manager->mm;
mutex_lock(&manager->lock);
- drm_buddy_free_list(mm, &mock_res->blocks, 0);
+ gpu_buddy_free_list(mm, &mock_res->blocks, 0);
mutex_unlock(&manager->lock);
ttm_resource_fini(man, res);
@@ -102,7 +102,7 @@ int ttm_mock_manager_init(struct ttm_dev
mutex_init(&manager->lock);
- err = drm_buddy_init(&manager->mm, size, PAGE_SIZE);
+ err = gpu_buddy_init(&manager->mm, size, PAGE_SIZE);
if (err) {
kfree(manager);
@@ -138,7 +138,7 @@ void ttm_mock_manager_fini(struct ttm_de
ttm_resource_manager_set_used(man, false);
mutex_lock(&mock_man->lock);
- drm_buddy_fini(&mock_man->mm);
+ gpu_buddy_fini(&mock_man->mm);
mutex_unlock(&mock_man->lock);
ttm_set_driver_manager(bdev, mem_type, NULL);
--- a/drivers/gpu/drm/ttm/tests/ttm_mock_manager.h
+++ b/drivers/gpu/drm/ttm/tests/ttm_mock_manager.h
@@ -5,11 +5,11 @@
#ifndef TTM_MOCK_MANAGER_H
#define TTM_MOCK_MANAGER_H
-#include <drm/drm_buddy.h>
+#include <linux/gpu_buddy.h>
struct ttm_mock_manager {
struct ttm_resource_manager man;
- struct drm_buddy mm;
+ struct gpu_buddy mm;
u64 default_page_size;
/* protects allocations of mock buffer objects */
struct mutex lock;
--- a/drivers/gpu/drm/xe/xe_res_cursor.h
+++ b/drivers/gpu/drm/xe/xe_res_cursor.h
@@ -44,10 +44,10 @@ struct xe_res_cursor {
void *node;
u32 mem_type;
struct scatterlist *sgl;
- struct drm_buddy *mm;
+ struct gpu_buddy *mm;
};
-static struct drm_buddy *xe_res_get_buddy(struct ttm_resource *res)
+static struct gpu_buddy *xe_res_get_buddy(struct ttm_resource *res)
{
struct ttm_resource_manager *mgr;
@@ -81,30 +81,30 @@ static inline void xe_res_first(struct t
case XE_PL_STOLEN:
case XE_PL_VRAM0:
case XE_PL_VRAM1: {
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
struct list_head *head, *next;
- struct drm_buddy *mm = xe_res_get_buddy(res);
+ struct gpu_buddy *mm = xe_res_get_buddy(res);
head = &to_xe_ttm_vram_mgr_resource(res)->blocks;
block = list_first_entry_or_null(head,
- struct drm_buddy_block,
+ struct gpu_buddy_block,
link);
if (!block)
goto fallback;
- while (start >= drm_buddy_block_size(mm, block)) {
- start -= drm_buddy_block_size(mm, block);
+ while (start >= gpu_buddy_block_size(mm, block)) {
+ start -= gpu_buddy_block_size(mm, block);
next = block->link.next;
if (next != head)
- block = list_entry(next, struct drm_buddy_block,
+ block = list_entry(next, struct gpu_buddy_block,
link);
}
cur->mm = mm;
- cur->start = drm_buddy_block_offset(block) + start;
- cur->size = min(drm_buddy_block_size(mm, block) - start,
+ cur->start = gpu_buddy_block_offset(block) + start;
+ cur->size = min(gpu_buddy_block_size(mm, block) - start,
size);
cur->remaining = size;
cur->node = block;
@@ -175,7 +175,7 @@ static inline void xe_res_first_sg(const
*/
static inline void xe_res_next(struct xe_res_cursor *cur, u64 size)
{
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
struct list_head *next;
u64 start;
@@ -205,18 +205,18 @@ static inline void xe_res_next(struct xe
block = cur->node;
next = block->link.next;
- block = list_entry(next, struct drm_buddy_block, link);
+ block = list_entry(next, struct gpu_buddy_block, link);
- while (start >= drm_buddy_block_size(cur->mm, block)) {
- start -= drm_buddy_block_size(cur->mm, block);
+ while (start >= gpu_buddy_block_size(cur->mm, block)) {
+ start -= gpu_buddy_block_size(cur->mm, block);
next = block->link.next;
- block = list_entry(next, struct drm_buddy_block, link);
+ block = list_entry(next, struct gpu_buddy_block, link);
}
- cur->start = drm_buddy_block_offset(block) + start;
- cur->size = min(drm_buddy_block_size(cur->mm, block) - start,
+ cur->start = gpu_buddy_block_offset(block) + start;
+ cur->size = min(gpu_buddy_block_size(cur->mm, block) - start,
cur->remaining);
cur->node = block;
break;
--- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
+++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
@@ -5,6 +5,7 @@
*/
#include <drm/drm_managed.h>
+#include <drm/drm_buddy.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
@@ -15,16 +16,16 @@
#include "xe_res_cursor.h"
#include "xe_ttm_vram_mgr.h"
-static inline struct drm_buddy_block *
+static inline struct gpu_buddy_block *
xe_ttm_vram_mgr_first_block(struct list_head *list)
{
- return list_first_entry_or_null(list, struct drm_buddy_block, link);
+ return list_first_entry_or_null(list, struct gpu_buddy_block, link);
}
-static inline bool xe_is_vram_mgr_blocks_contiguous(struct drm_buddy *mm,
+static inline bool xe_is_vram_mgr_blocks_contiguous(struct gpu_buddy *mm,
struct list_head *head)
{
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
u64 start, size;
block = xe_ttm_vram_mgr_first_block(head);
@@ -32,12 +33,12 @@ static inline bool xe_is_vram_mgr_blocks
return false;
while (head != block->link.next) {
- start = drm_buddy_block_offset(block);
- size = drm_buddy_block_size(mm, block);
+ start = gpu_buddy_block_offset(block);
+ size = gpu_buddy_block_size(mm, block);
- block = list_entry(block->link.next, struct drm_buddy_block,
+ block = list_entry(block->link.next, struct gpu_buddy_block,
link);
- if (start + size != drm_buddy_block_offset(block))
+ if (start + size != gpu_buddy_block_offset(block))
return false;
}
@@ -51,7 +52,7 @@ static int xe_ttm_vram_mgr_new(struct tt
{
struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man);
struct xe_ttm_vram_mgr_resource *vres;
- struct drm_buddy *mm = &mgr->mm;
+ struct gpu_buddy *mm = &mgr->mm;
u64 size, remaining_size, min_page_size;
unsigned long lpfn;
int err;
@@ -78,10 +79,10 @@ static int xe_ttm_vram_mgr_new(struct tt
INIT_LIST_HEAD(&vres->blocks);
if (place->flags & TTM_PL_FLAG_TOPDOWN)
- vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
+ vres->flags |= GPU_BUDDY_TOPDOWN_ALLOCATION;
if (place->fpfn || lpfn != man->size >> PAGE_SHIFT)
- vres->flags |= DRM_BUDDY_RANGE_ALLOCATION;
+ vres->flags |= GPU_BUDDY_RANGE_ALLOCATION;
if (WARN_ON(!vres->base.size)) {
err = -EINVAL;
@@ -137,7 +138,7 @@ static int xe_ttm_vram_mgr_new(struct tt
*/
u64 alloc_size = min_t(u64, remaining_size, SZ_2G);
- err = drm_buddy_alloc_blocks(mm, (u64)place->fpfn << PAGE_SHIFT,
+ err = gpu_buddy_alloc_blocks(mm, (u64)place->fpfn << PAGE_SHIFT,
(u64)lpfn << PAGE_SHIFT,
alloc_size,
min_page_size,
@@ -150,20 +151,20 @@ static int xe_ttm_vram_mgr_new(struct tt
} while (remaining_size);
if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
- if (!drm_buddy_block_trim(mm, NULL, vres->base.size, &vres->blocks))
+ if (!gpu_buddy_block_trim(mm, NULL, vres->base.size, &vres->blocks))
size = vres->base.size;
}
if (lpfn <= mgr->visible_size >> PAGE_SHIFT) {
vres->used_visible_size = size;
} else {
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
list_for_each_entry(block, &vres->blocks, link) {
- u64 start = drm_buddy_block_offset(block);
+ u64 start = gpu_buddy_block_offset(block);
if (start < mgr->visible_size) {
- u64 end = start + drm_buddy_block_size(mm, block);
+ u64 end = start + gpu_buddy_block_size(mm, block);
vres->used_visible_size +=
min(end, mgr->visible_size) - start;
@@ -183,11 +184,11 @@ static int xe_ttm_vram_mgr_new(struct tt
* the object.
*/
if (vres->base.placement & TTM_PL_FLAG_CONTIGUOUS) {
- struct drm_buddy_block *block = list_first_entry(&vres->blocks,
+ struct gpu_buddy_block *block = list_first_entry(&vres->blocks,
typeof(*block),
link);
- vres->base.start = drm_buddy_block_offset(block) >> PAGE_SHIFT;
+ vres->base.start = gpu_buddy_block_offset(block) >> PAGE_SHIFT;
} else {
vres->base.start = XE_BO_INVALID_OFFSET;
}
@@ -196,7 +197,7 @@ static int xe_ttm_vram_mgr_new(struct tt
return 0;
error_free_blocks:
- drm_buddy_free_list(mm, &vres->blocks, 0);
+ gpu_buddy_free_list(mm, &vres->blocks, 0);
mutex_unlock(&mgr->lock);
error_fini:
ttm_resource_fini(man, &vres->base);
@@ -211,10 +212,10 @@ static void xe_ttm_vram_mgr_del(struct t
struct xe_ttm_vram_mgr_resource *vres =
to_xe_ttm_vram_mgr_resource(res);
struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man);
- struct drm_buddy *mm = &mgr->mm;
+ struct gpu_buddy *mm = &mgr->mm;
mutex_lock(&mgr->lock);
- drm_buddy_free_list(mm, &vres->blocks, 0);
+ gpu_buddy_free_list(mm, &vres->blocks, 0);
mgr->visible_avail += vres->used_visible_size;
mutex_unlock(&mgr->lock);
@@ -227,7 +228,7 @@ static void xe_ttm_vram_mgr_debug(struct
struct drm_printer *printer)
{
struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man);
- struct drm_buddy *mm = &mgr->mm;
+ struct gpu_buddy *mm = &mgr->mm;
mutex_lock(&mgr->lock);
drm_printf(printer, "default_page_size: %lluKiB\n",
@@ -250,8 +251,8 @@ static bool xe_ttm_vram_mgr_intersects(s
struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man);
struct xe_ttm_vram_mgr_resource *vres =
to_xe_ttm_vram_mgr_resource(res);
- struct drm_buddy *mm = &mgr->mm;
- struct drm_buddy_block *block;
+ struct gpu_buddy *mm = &mgr->mm;
+ struct gpu_buddy_block *block;
if (!place->fpfn && !place->lpfn)
return true;
@@ -261,9 +262,9 @@ static bool xe_ttm_vram_mgr_intersects(s
list_for_each_entry(block, &vres->blocks, link) {
unsigned long fpfn =
- drm_buddy_block_offset(block) >> PAGE_SHIFT;
+ gpu_buddy_block_offset(block) >> PAGE_SHIFT;
unsigned long lpfn = fpfn +
- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT);
+ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT);
if (place->fpfn < lpfn && place->lpfn > fpfn)
return true;
@@ -280,8 +281,8 @@ static bool xe_ttm_vram_mgr_compatible(s
struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man);
struct xe_ttm_vram_mgr_resource *vres =
to_xe_ttm_vram_mgr_resource(res);
- struct drm_buddy *mm = &mgr->mm;
- struct drm_buddy_block *block;
+ struct gpu_buddy *mm = &mgr->mm;
+ struct gpu_buddy_block *block;
if (!place->fpfn && !place->lpfn)
return true;
@@ -291,9 +292,9 @@ static bool xe_ttm_vram_mgr_compatible(s
list_for_each_entry(block, &vres->blocks, link) {
unsigned long fpfn =
- drm_buddy_block_offset(block) >> PAGE_SHIFT;
+ gpu_buddy_block_offset(block) >> PAGE_SHIFT;
unsigned long lpfn = fpfn +
- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT);
+ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT);
if (fpfn < place->fpfn || lpfn > place->lpfn)
return false;
@@ -323,7 +324,7 @@ static void ttm_vram_mgr_fini(struct drm
WARN_ON_ONCE(mgr->visible_avail != mgr->visible_size);
- drm_buddy_fini(&mgr->mm);
+ gpu_buddy_fini(&mgr->mm);
ttm_resource_manager_cleanup(&mgr->manager);
@@ -347,7 +348,7 @@ int __xe_ttm_vram_mgr_init(struct xe_dev
mgr->visible_avail = io_size;
ttm_resource_manager_init(man, &xe->ttm, size);
- err = drm_buddy_init(&mgr->mm, man->size, default_page_size);
+ err = gpu_buddy_init(&mgr->mm, man->size, default_page_size);
if (err)
return err;
@@ -389,7 +390,7 @@ int xe_ttm_vram_mgr_alloc_sgt(struct xe_
if (!*sgt)
return -ENOMEM;
- /* Determine the number of DRM_BUDDY blocks to export */
+ /* Determine the number of GPU_BUDDY blocks to export */
xe_res_first(res, offset, length, &cursor);
while (cursor.remaining) {
num_entries++;
@@ -405,10 +406,10 @@ int xe_ttm_vram_mgr_alloc_sgt(struct xe_
sg->length = 0;
/*
- * Walk down DRM_BUDDY blocks to populate scatterlist nodes
- * @note: Use iterator api to get first the DRM_BUDDY block
+ * Walk down GPU_BUDDY blocks to populate scatterlist nodes
+ * @note: Use iterator api to get first the GPU_BUDDY block
* and the number of bytes from it. Access the following
- * DRM_BUDDY block(s) if more buffer needs to exported
+ * GPU_BUDDY block(s) if more buffer needs to exported
*/
xe_res_first(res, offset, length, &cursor);
for_each_sgtable_sg((*sgt), sg, i) {
--- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h
+++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h
@@ -6,7 +6,7 @@
#ifndef _XE_TTM_VRAM_MGR_TYPES_H_
#define _XE_TTM_VRAM_MGR_TYPES_H_
-#include <drm/drm_buddy.h>
+#include <linux/gpu_buddy.h>
#include <drm/ttm/ttm_device.h>
struct xe_mem_region;
@@ -20,7 +20,7 @@ struct xe_ttm_vram_mgr {
/** @manager: Base TTM resource manager */
struct ttm_resource_manager manager;
/** @mm: DRM buddy allocator which manages the VRAM */
- struct drm_buddy mm;
+ struct gpu_buddy mm;
/** @vram: ptr to details of associated VRAM region */
struct xe_mem_region *vram;
/** @visible_size: Proped size of the CPU visible portion */
--- /dev/null
+++ b/drivers/gpu/tests/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+gpu_buddy_tests-y = gpu_buddy_test.o gpu_random.o
+obj-$(CONFIG_GPU_BUDDY_KUNIT_TEST) += gpu_buddy_tests.o
--- /dev/null
+++ b/drivers/gpu/tests/gpu_buddy_test.c
@@ -0,0 +1,778 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2019 Intel Corporation
+ * Copyright © 2022 Maíra Canal <mairacanal@riseup.net>
+ */
+
+#include <kunit/test.h>
+
+#include <linux/prime_numbers.h>
+#include <linux/sched/signal.h>
+#include <linux/sizes.h>
+
+#include <linux/gpu_buddy.h>
+
+#include "gpu_random.h"
+
+static unsigned int random_seed;
+
+static inline u64 get_size(int order, u64 chunk_size)
+{
+ return (1 << order) * chunk_size;
+}
+
+static void drm_test_buddy_alloc_range_bias(struct kunit *test)
+{
+ u32 mm_size, size, ps, bias_size, bias_start, bias_end, bias_rem;
+ GPU_RND_STATE(prng, random_seed);
+ unsigned int i, count, *order;
+ struct gpu_buddy_block *block;
+ unsigned long flags;
+ struct gpu_buddy mm;
+ LIST_HEAD(allocated);
+
+ bias_size = SZ_1M;
+ ps = roundup_pow_of_two(prandom_u32_state(&prng) % bias_size);
+ ps = max(SZ_4K, ps);
+ mm_size = (SZ_8M-1) & ~(ps-1); /* Multiple roots */
+
+ kunit_info(test, "mm_size=%u, ps=%u\n", mm_size, ps);
+
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps),
+ "buddy_init failed\n");
+
+ count = mm_size / bias_size;
+ order = gpu_random_order(count, &prng);
+ KUNIT_EXPECT_TRUE(test, order);
+
+ /*
+ * Idea is to split the address space into uniform bias ranges, and then
+ * in some random order allocate within each bias, using various
+ * patterns within. This should detect if allocations leak out from a
+ * given bias, for example.
+ */
+
+ for (i = 0; i < count; i++) {
+ LIST_HEAD(tmp);
+ u32 size;
+
+ bias_start = order[i] * bias_size;
+ bias_end = bias_start + bias_size;
+ bias_rem = bias_size;
+
+ /* internal round_up too big */
+ KUNIT_ASSERT_TRUE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, bias_size + ps, bias_size,
+ &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, bias_size, bias_size);
+
+ /* size too big */
+ KUNIT_ASSERT_TRUE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, bias_size + ps, ps,
+ &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, bias_size + ps, ps);
+
+ /* bias range too small for size */
+ KUNIT_ASSERT_TRUE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start + ps,
+ bias_end, bias_size, ps,
+ &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start + ps, bias_end, bias_size, ps);
+
+ /* bias misaligned */
+ KUNIT_ASSERT_TRUE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start + ps,
+ bias_end - ps,
+ bias_size >> 1, bias_size >> 1,
+ &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc h didn't fail with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start + ps, bias_end - ps, bias_size >> 1, bias_size >> 1);
+
+ /* single big page */
+ KUNIT_ASSERT_FALSE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, bias_size, bias_size,
+ &tmp,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, bias_size, bias_size);
+ gpu_buddy_free_list(&mm, &tmp, 0);
+
+ /* single page with internal round_up */
+ KUNIT_ASSERT_FALSE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, ps, bias_size,
+ &tmp,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, ps, bias_size);
+ gpu_buddy_free_list(&mm, &tmp, 0);
+
+ /* random size within */
+ size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
+ if (size)
+ KUNIT_ASSERT_FALSE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, size, ps,
+ &tmp,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, size, ps);
+
+ bias_rem -= size;
+ /* too big for current avail */
+ KUNIT_ASSERT_TRUE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, bias_rem + ps, ps,
+ &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, bias_rem + ps, ps);
+
+ if (bias_rem) {
+ /* random fill of the remainder */
+ size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
+ size = max(size, ps);
+
+ KUNIT_ASSERT_FALSE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, size, ps,
+ &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, size, ps);
+ /*
+ * Intentionally allow some space to be left
+ * unallocated, and ideally not always on the bias
+ * boundaries.
+ */
+ gpu_buddy_free_list(&mm, &tmp, 0);
+ } else {
+ list_splice_tail(&tmp, &allocated);
+ }
+ }
+
+ kfree(order);
+ gpu_buddy_free_list(&mm, &allocated, 0);
+ gpu_buddy_fini(&mm);
+
+ /*
+ * Something more free-form. Idea is to pick a random starting bias
+ * range within the address space and then start filling it up. Also
+ * randomly grow the bias range in both directions as we go along. This
+ * should give us bias start/end which is not always uniform like above,
+ * and in some cases will require the allocator to jump over already
+ * allocated nodes in the middle of the address space.
+ */
+
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps),
+ "buddy_init failed\n");
+
+ bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps);
+ bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps);
+ bias_end = max(bias_end, bias_start + ps);
+ bias_rem = bias_end - bias_start;
+
+ do {
+ u32 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
+
+ KUNIT_ASSERT_FALSE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, size, ps,
+ &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, size, ps);
+ bias_rem -= size;
+
+ /*
+ * Try to randomly grow the bias range in both directions, or
+ * only one, or perhaps don't grow at all.
+ */
+ do {
+ u32 old_bias_start = bias_start;
+ u32 old_bias_end = bias_end;
+
+ if (bias_start)
+ bias_start -= round_up(prandom_u32_state(&prng) % bias_start, ps);
+ if (bias_end != mm_size)
+ bias_end += round_up(prandom_u32_state(&prng) % (mm_size - bias_end), ps);
+
+ bias_rem += old_bias_start - bias_start;
+ bias_rem += bias_end - old_bias_end;
+ } while (!bias_rem && (bias_start || bias_end != mm_size));
+ } while (bias_rem);
+
+ KUNIT_ASSERT_EQ(test, bias_start, 0);
+ KUNIT_ASSERT_EQ(test, bias_end, mm_size);
+ KUNIT_ASSERT_TRUE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start, bias_end,
+ ps, ps,
+ &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc passed with bias(%x-%x), size=%u\n",
+ bias_start, bias_end, ps);
+
+ gpu_buddy_free_list(&mm, &allocated, 0);
+ gpu_buddy_fini(&mm);
+
+ /*
+ * Allocate cleared blocks in the bias range when the DRM buddy's clear avail is
+ * zero. This will validate the bias range allocation in scenarios like system boot
+ * when no cleared blocks are available and exercise the fallback path too. The resulting
+ * blocks should always be dirty.
+ */
+
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps),
+ "buddy_init failed\n");
+
+ bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps);
+ bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps);
+ bias_end = max(bias_end, bias_start + ps);
+ bias_rem = bias_end - bias_start;
+
+ flags = GPU_BUDDY_CLEAR_ALLOCATION | GPU_BUDDY_RANGE_ALLOCATION;
+ size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps);
+
+ KUNIT_ASSERT_FALSE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, bias_start,
+ bias_end, size, ps,
+ &allocated,
+ flags),
+ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n",
+ bias_start, bias_end, size, ps);
+
+ list_for_each_entry(block, &allocated, link)
+ KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false);
+
+ gpu_buddy_free_list(&mm, &allocated, 0);
+ gpu_buddy_fini(&mm);
+}
+
+static void drm_test_buddy_alloc_clear(struct kunit *test)
+{
+ unsigned long n_pages, total, i = 0;
+ GPU_RND_STATE(prng, random_seed);
+ const unsigned long ps = SZ_4K;
+ struct gpu_buddy_block *block;
+ const int max_order = 12;
+ LIST_HEAD(allocated);
+ struct gpu_buddy mm;
+ unsigned int order;
+ u32 mm_size, size;
+ LIST_HEAD(dirty);
+ LIST_HEAD(clean);
+
+ mm_size = SZ_4K << max_order;
+ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
+
+ KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
+
+ /*
+ * Idea is to allocate and free some random portion of the address space,
+ * returning those pages as non-dirty and randomly alternate between
+ * requesting dirty and non-dirty pages (not going over the limit
+ * we freed as non-dirty), putting that into two separate lists.
+ * Loop over both lists at the end checking that the dirty list
+ * is indeed all dirty pages and vice versa. Free it all again,
+ * keeping the dirty/clear status.
+ */
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ 5 * ps, ps, &allocated,
+ GPU_BUDDY_TOPDOWN_ALLOCATION),
+ "buddy_alloc hit an error size=%lu\n", 5 * ps);
+ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
+
+ n_pages = 10;
+ do {
+ unsigned long flags;
+ struct list_head *list;
+ int slot = i % 2;
+
+ if (slot == 0) {
+ list = &dirty;
+ flags = 0;
+ } else {
+ list = &clean;
+ flags = GPU_BUDDY_CLEAR_ALLOCATION;
+ }
+
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ ps, ps, list,
+ flags),
+ "buddy_alloc hit an error size=%lu\n", ps);
+ } while (++i < n_pages);
+
+ list_for_each_entry(block, &clean, link)
+ KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), true);
+
+ list_for_each_entry(block, &dirty, link)
+ KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false);
+
+ gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED);
+
+ /*
+ * Trying to go over the clear limit for some allocation.
+ * The allocation should never fail with reasonable page-size.
+ */
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ 10 * ps, ps, &clean,
+ GPU_BUDDY_CLEAR_ALLOCATION),
+ "buddy_alloc hit an error size=%lu\n", 10 * ps);
+
+ gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED);
+ gpu_buddy_free_list(&mm, &dirty, 0);
+ gpu_buddy_fini(&mm);
+
+ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
+
+ /*
+ * Create a new mm. Intentionally fragment the address space by creating
+ * two alternating lists. Free both lists, one as dirty the other as clean.
+ * Try to allocate double the previous size with matching min_page_size. The
+ * allocation should never fail as it calls the force_merge. Also check that
+ * the page is always dirty after force_merge. Free the page as dirty, then
+ * repeat the whole thing, increment the order until we hit the max_order.
+ */
+
+ i = 0;
+ n_pages = mm_size / ps;
+ do {
+ struct list_head *list;
+ int slot = i % 2;
+
+ if (slot == 0)
+ list = &dirty;
+ else
+ list = &clean;
+
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ ps, ps, list, 0),
+ "buddy_alloc hit an error size=%lu\n", ps);
+ } while (++i < n_pages);
+
+ gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED);
+ gpu_buddy_free_list(&mm, &dirty, 0);
+
+ order = 1;
+ do {
+ size = SZ_4K << order;
+
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ size, size, &allocated,
+ GPU_BUDDY_CLEAR_ALLOCATION),
+ "buddy_alloc hit an error size=%u\n", size);
+ total = 0;
+ list_for_each_entry(block, &allocated, link) {
+ if (size != mm_size)
+ KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false);
+ total += gpu_buddy_block_size(&mm, block);
+ }
+ KUNIT_EXPECT_EQ(test, total, size);
+
+ gpu_buddy_free_list(&mm, &allocated, 0);
+ } while (++order <= max_order);
+
+ gpu_buddy_fini(&mm);
+
+ /*
+ * Create a new mm with a non power-of-two size. Allocate a random size, free as
+ * cleared and then call fini. This will ensure the multi-root force merge during
+ * fini.
+ */
+ mm_size = 12 * SZ_4K;
+ size = max(round_up(prandom_u32_state(&prng) % mm_size, ps), ps);
+ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ size, ps, &allocated,
+ GPU_BUDDY_TOPDOWN_ALLOCATION),
+ "buddy_alloc hit an error size=%u\n", size);
+ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
+ gpu_buddy_fini(&mm);
+}
+
+static void drm_test_buddy_alloc_contiguous(struct kunit *test)
+{
+ const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K;
+ unsigned long i, n_pages, total;
+ struct gpu_buddy_block *block;
+ struct gpu_buddy mm;
+ LIST_HEAD(left);
+ LIST_HEAD(middle);
+ LIST_HEAD(right);
+ LIST_HEAD(allocated);
+
+ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
+
+ /*
+ * Idea is to fragment the address space by alternating block
+ * allocations between three different lists; one for left, middle and
+ * right. We can then free a list to simulate fragmentation. In
+ * particular we want to exercise the GPU_BUDDY_CONTIGUOUS_ALLOCATION,
+ * including the try_harder path.
+ */
+
+ i = 0;
+ n_pages = mm_size / ps;
+ do {
+ struct list_head *list;
+ int slot = i % 3;
+
+ if (slot == 0)
+ list = &left;
+ else if (slot == 1)
+ list = &middle;
+ else
+ list = &right;
+ KUNIT_ASSERT_FALSE_MSG(test,
+ gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ ps, ps, list, 0),
+ "buddy_alloc hit an error size=%lu\n",
+ ps);
+ } while (++i < n_pages);
+
+ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ 3 * ps, ps, &allocated,
+ GPU_BUDDY_CONTIGUOUS_ALLOCATION),
+ "buddy_alloc didn't error size=%lu\n", 3 * ps);
+
+ gpu_buddy_free_list(&mm, &middle, 0);
+ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ 3 * ps, ps, &allocated,
+ GPU_BUDDY_CONTIGUOUS_ALLOCATION),
+ "buddy_alloc didn't error size=%lu\n", 3 * ps);
+ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ 2 * ps, ps, &allocated,
+ GPU_BUDDY_CONTIGUOUS_ALLOCATION),
+ "buddy_alloc didn't error size=%lu\n", 2 * ps);
+
+ gpu_buddy_free_list(&mm, &right, 0);
+ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ 3 * ps, ps, &allocated,
+ GPU_BUDDY_CONTIGUOUS_ALLOCATION),
+ "buddy_alloc didn't error size=%lu\n", 3 * ps);
+ /*
+ * At this point we should have enough contiguous space for 2 blocks,
+ * however they are never buddies (since we freed middle and right) so
+ * will require the try_harder logic to find them.
+ */
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ 2 * ps, ps, &allocated,
+ GPU_BUDDY_CONTIGUOUS_ALLOCATION),
+ "buddy_alloc hit an error size=%lu\n", 2 * ps);
+
+ gpu_buddy_free_list(&mm, &left, 0);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size,
+ 3 * ps, ps, &allocated,
+ GPU_BUDDY_CONTIGUOUS_ALLOCATION),
+ "buddy_alloc hit an error size=%lu\n", 3 * ps);
+
+ total = 0;
+ list_for_each_entry(block, &allocated, link)
+ total += gpu_buddy_block_size(&mm, block);
+
+ KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3);
+
+ gpu_buddy_free_list(&mm, &allocated, 0);
+ gpu_buddy_fini(&mm);
+}
+
+static void drm_test_buddy_alloc_pathological(struct kunit *test)
+{
+ u64 mm_size, size, start = 0;
+ struct gpu_buddy_block *block;
+ const int max_order = 3;
+ unsigned long flags = 0;
+ int order, top;
+ struct gpu_buddy mm;
+ LIST_HEAD(blocks);
+ LIST_HEAD(holes);
+ LIST_HEAD(tmp);
+
+ /*
+ * Create a pot-sized mm, then allocate one of each possible
+ * order within. This should leave the mm with exactly one
+ * page left. Free the largest block, then whittle down again.
+ * Eventually we will have a fully 50% fragmented mm.
+ */
+
+ mm_size = SZ_4K << max_order;
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
+ "buddy_init failed\n");
+
+ KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
+
+ for (top = max_order; top; top--) {
+ /* Make room by freeing the largest allocated block */
+ block = list_first_entry_or_null(&blocks, typeof(*block), link);
+ if (block) {
+ list_del(&block->link);
+ gpu_buddy_free_block(&mm, block);
+ }
+
+ for (order = top; order--;) {
+ size = get_size(order, mm.chunk_size);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start,
+ mm_size, size, size,
+ &tmp, flags),
+ "buddy_alloc hit -ENOMEM with order=%d, top=%d\n",
+ order, top);
+
+ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
+ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
+
+ list_move_tail(&block->link, &blocks);
+ }
+
+ /* There should be one final page for this sub-allocation */
+ size = get_size(0, mm.chunk_size);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc hit -ENOMEM for hole\n");
+
+ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
+ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
+
+ list_move_tail(&block->link, &holes);
+
+ size = get_size(top, mm.chunk_size);
+ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!",
+ top, max_order);
+ }
+
+ gpu_buddy_free_list(&mm, &holes, 0);
+
+ /* Nothing larger than blocks of chunk_size now available */
+ for (order = 1; order <= max_order; order++) {
+ size = get_size(order, mm.chunk_size);
+ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc unexpectedly succeeded at order %d, it should be full!",
+ order);
+ }
+
+ list_splice_tail(&holes, &blocks);
+ gpu_buddy_free_list(&mm, &blocks, 0);
+ gpu_buddy_fini(&mm);
+}
+
+static void drm_test_buddy_alloc_pessimistic(struct kunit *test)
+{
+ u64 mm_size, size, start = 0;
+ struct gpu_buddy_block *block, *bn;
+ const unsigned int max_order = 16;
+ unsigned long flags = 0;
+ struct gpu_buddy mm;
+ unsigned int order;
+ LIST_HEAD(blocks);
+ LIST_HEAD(tmp);
+
+ /*
+ * Create a pot-sized mm, then allocate one of each possible
+ * order within. This should leave the mm with exactly one
+ * page left.
+ */
+
+ mm_size = SZ_4K << max_order;
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
+ "buddy_init failed\n");
+
+ KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
+
+ for (order = 0; order < max_order; order++) {
+ size = get_size(order, mm.chunk_size);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc hit -ENOMEM with order=%d\n",
+ order);
+
+ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
+ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
+
+ list_move_tail(&block->link, &blocks);
+ }
+
+ /* And now the last remaining block available */
+ size = get_size(0, mm.chunk_size);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc hit -ENOMEM on final alloc\n");
+
+ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
+ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
+
+ list_move_tail(&block->link, &blocks);
+
+ /* Should be completely full! */
+ for (order = max_order; order--;) {
+ size = get_size(order, mm.chunk_size);
+ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc unexpectedly succeeded, it should be full!");
+ }
+
+ block = list_last_entry(&blocks, typeof(*block), link);
+ list_del(&block->link);
+ gpu_buddy_free_block(&mm, block);
+
+ /* As we free in increasing size, we make available larger blocks */
+ order = 1;
+ list_for_each_entry_safe(block, bn, &blocks, link) {
+ list_del(&block->link);
+ gpu_buddy_free_block(&mm, block);
+
+ size = get_size(order, mm.chunk_size);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc hit -ENOMEM with order=%d\n",
+ order);
+
+ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
+ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
+
+ list_del(&block->link);
+ gpu_buddy_free_block(&mm, block);
+ order++;
+ }
+
+ /* To confirm, now the whole mm should be available */
+ size = get_size(max_order, mm.chunk_size);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc (realloc) hit -ENOMEM with order=%d\n",
+ max_order);
+
+ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
+ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
+
+ list_del(&block->link);
+ gpu_buddy_free_block(&mm, block);
+ gpu_buddy_free_list(&mm, &blocks, 0);
+ gpu_buddy_fini(&mm);
+}
+
+static void drm_test_buddy_alloc_optimistic(struct kunit *test)
+{
+ u64 mm_size, size, start = 0;
+ struct gpu_buddy_block *block;
+ unsigned long flags = 0;
+ const int max_order = 16;
+ struct gpu_buddy mm;
+ LIST_HEAD(blocks);
+ LIST_HEAD(tmp);
+ int order;
+
+ /*
+ * Create a mm with one block of each order available, and
+ * try to allocate them all.
+ */
+
+ mm_size = SZ_4K * ((1 << (max_order + 1)) - 1);
+
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K),
+ "buddy_init failed\n");
+
+ KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
+
+ for (order = 0; order <= max_order; order++) {
+ size = get_size(order, mm.chunk_size);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc hit -ENOMEM with order=%d\n",
+ order);
+
+ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link);
+ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n");
+
+ list_move_tail(&block->link, &blocks);
+ }
+
+ /* Should be completely full! */
+ size = get_size(0, mm.chunk_size);
+ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size,
+ size, size, &tmp, flags),
+ "buddy_alloc unexpectedly succeeded, it should be full!");
+
+ gpu_buddy_free_list(&mm, &blocks, 0);
+ gpu_buddy_fini(&mm);
+}
+
+static void drm_test_buddy_alloc_limit(struct kunit *test)
+{
+ u64 size = U64_MAX, start = 0;
+ struct gpu_buddy_block *block;
+ unsigned long flags = 0;
+ LIST_HEAD(allocated);
+ struct gpu_buddy mm;
+
+ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, size, SZ_4K));
+
+ KUNIT_EXPECT_EQ_MSG(test, mm.max_order, GPU_BUDDY_MAX_ORDER,
+ "mm.max_order(%d) != %d\n", mm.max_order,
+ GPU_BUDDY_MAX_ORDER);
+
+ size = mm.chunk_size << mm.max_order;
+ KUNIT_EXPECT_FALSE(test, gpu_buddy_alloc_blocks(&mm, start, size, size,
+ mm.chunk_size, &allocated, flags));
+
+ block = list_first_entry_or_null(&allocated, struct gpu_buddy_block, link);
+ KUNIT_EXPECT_TRUE(test, block);
+
+ KUNIT_EXPECT_EQ_MSG(test, gpu_buddy_block_order(block), mm.max_order,
+ "block order(%d) != %d\n",
+ gpu_buddy_block_order(block), mm.max_order);
+
+ KUNIT_EXPECT_EQ_MSG(test, gpu_buddy_block_size(&mm, block),
+ BIT_ULL(mm.max_order) * mm.chunk_size,
+ "block size(%llu) != %llu\n",
+ gpu_buddy_block_size(&mm, block),
+ BIT_ULL(mm.max_order) * mm.chunk_size);
+
+ gpu_buddy_free_list(&mm, &allocated, 0);
+ gpu_buddy_fini(&mm);
+}
+
+static int gpu_buddy_suite_init(struct kunit_suite *suite)
+{
+ while (!random_seed)
+ random_seed = get_random_u32();
+
+ kunit_info(suite, "Testing DRM buddy manager, with random_seed=0x%x\n",
+ random_seed);
+
+ return 0;
+}
+
+static struct kunit_case gpu_buddy_tests[] = {
+ KUNIT_CASE(drm_test_buddy_alloc_limit),
+ KUNIT_CASE(drm_test_buddy_alloc_optimistic),
+ KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
+ KUNIT_CASE(drm_test_buddy_alloc_pathological),
+ KUNIT_CASE(drm_test_buddy_alloc_contiguous),
+ KUNIT_CASE(drm_test_buddy_alloc_clear),
+ KUNIT_CASE(drm_test_buddy_alloc_range_bias),
+ {}
+};
+
+static struct kunit_suite gpu_buddy_test_suite = {
+ .name = "gpu_buddy",
+ .suite_init = gpu_buddy_suite_init,
+ .test_cases = gpu_buddy_tests,
+};
+
+kunit_test_suite(gpu_buddy_test_suite);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Kunit test for gpu_buddy functions");
+MODULE_LICENSE("GPL");
--- /dev/null
+++ b/drivers/gpu/tests/gpu_random.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "gpu_random.h"
+
+u32 gpu_prandom_u32_max_state(u32 ep_ro, struct rnd_state *state)
+{
+ return upper_32_bits((u64)prandom_u32_state(state) * ep_ro);
+}
+EXPORT_SYMBOL(gpu_prandom_u32_max_state);
+
+void gpu_random_reorder(unsigned int *order, unsigned int count,
+ struct rnd_state *state)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < count; ++i) {
+ BUILD_BUG_ON(sizeof(unsigned int) > sizeof(u32));
+ j = gpu_prandom_u32_max_state(count, state);
+ swap(order[i], order[j]);
+ }
+}
+EXPORT_SYMBOL(gpu_random_reorder);
+
+unsigned int *gpu_random_order(unsigned int count, struct rnd_state *state)
+{
+ unsigned int *order, i;
+
+ order = kmalloc_array(count, sizeof(*order), GFP_KERNEL);
+ if (!order)
+ return order;
+
+ for (i = 0; i < count; i++)
+ order[i] = i;
+
+ gpu_random_reorder(order, count, state);
+ return order;
+}
+EXPORT_SYMBOL(gpu_random_order);
--- /dev/null
+++ b/drivers/gpu/tests/gpu_random.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __GPU_RANDOM_H__
+#define __GPU_RANDOM_H__
+
+/* This is a temporary home for a couple of utility functions that should
+ * be transposed to lib/ at the earliest convenience.
+ */
+
+#include <linux/random.h>
+
+#define GPU_RND_STATE_INITIALIZER(seed__) ({ \
+ struct rnd_state state__; \
+ prandom_seed_state(&state__, (seed__)); \
+ state__; \
+})
+
+#define GPU_RND_STATE(name__, seed__) \
+ struct rnd_state name__ = GPU_RND_STATE_INITIALIZER(seed__)
+
+unsigned int *gpu_random_order(unsigned int count,
+ struct rnd_state *state);
+void gpu_random_reorder(unsigned int *order,
+ unsigned int count,
+ struct rnd_state *state);
+u32 gpu_prandom_u32_max_state(u32 ep_ro,
+ struct rnd_state *state);
+
+#endif /* !__GPU_RANDOM_H__ */
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -37,6 +37,7 @@ source "drivers/char/agp/Kconfig"
source "drivers/gpu/vga/Kconfig"
+source "drivers/gpu/Kconfig"
source "drivers/gpu/host1x/Kconfig"
source "drivers/gpu/ipu-v3/Kconfig"
--- a/include/drm/drm_buddy.h
+++ b/include/drm/drm_buddy.h
@@ -6,175 +6,13 @@
#ifndef __DRM_BUDDY_H__
#define __DRM_BUDDY_H__
-#include <linux/bitops.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/rbtree.h>
+#include <linux/gpu_buddy.h>
-#include <drm/drm_print.h>
+struct drm_printer;
-#define range_overflows(start, size, max) ({ \
- typeof(start) start__ = (start); \
- typeof(size) size__ = (size); \
- typeof(max) max__ = (max); \
- (void)(&start__ == &size__); \
- (void)(&start__ == &max__); \
- start__ >= max__ || size__ > max__ - start__; \
-})
-
-#define DRM_BUDDY_RANGE_ALLOCATION BIT(0)
-#define DRM_BUDDY_TOPDOWN_ALLOCATION BIT(1)
-#define DRM_BUDDY_CONTIGUOUS_ALLOCATION BIT(2)
-#define DRM_BUDDY_CLEAR_ALLOCATION BIT(3)
-#define DRM_BUDDY_CLEARED BIT(4)
-#define DRM_BUDDY_TRIM_DISABLE BIT(5)
-
-struct drm_buddy_block {
-#define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
-#define DRM_BUDDY_HEADER_STATE GENMASK_ULL(11, 10)
-#define DRM_BUDDY_ALLOCATED (1 << 10)
-#define DRM_BUDDY_FREE (2 << 10)
-#define DRM_BUDDY_SPLIT (3 << 10)
-#define DRM_BUDDY_HEADER_CLEAR GENMASK_ULL(9, 9)
-/* Free to be used, if needed in the future */
-#define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(8, 6)
-#define DRM_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0)
- u64 header;
-
- struct drm_buddy_block *left;
- struct drm_buddy_block *right;
- struct drm_buddy_block *parent;
-
- void *private; /* owned by creator */
-
- /*
- * While the block is allocated by the user through drm_buddy_alloc*,
- * the user has ownership of the link, for example to maintain within
- * a list, if so desired. As soon as the block is freed with
- * drm_buddy_free* ownership is given back to the mm.
- */
- union {
- struct rb_node rb;
- struct list_head link;
- };
-
- struct list_head tmp_link;
-};
-
-/* Order-zero must be at least SZ_4K */
-#define DRM_BUDDY_MAX_ORDER (63 - 12)
-
-/*
- * Binary Buddy System.
- *
- * Locking should be handled by the user, a simple mutex around
- * drm_buddy_alloc* and drm_buddy_free* should suffice.
- */
-struct drm_buddy {
- /* Maintain a free list for each order. */
- struct rb_root **free_trees;
-
- /*
- * Maintain explicit binary tree(s) to track the allocation of the
- * address space. This gives us a simple way of finding a buddy block
- * and performing the potentially recursive merge step when freeing a
- * block. Nodes are either allocated or free, in which case they will
- * also exist on the respective free list.
- */
- struct drm_buddy_block **roots;
-
- /*
- * Anything from here is public, and remains static for the lifetime of
- * the mm. Everything above is considered do-not-touch.
- */
- unsigned int n_roots;
- unsigned int max_order;
-
- /* Must be at least SZ_4K */
- u64 chunk_size;
- u64 size;
- u64 avail;
- u64 clear_avail;
-};
-
-static inline u64
-drm_buddy_block_offset(const struct drm_buddy_block *block)
-{
- return block->header & DRM_BUDDY_HEADER_OFFSET;
-}
-
-static inline unsigned int
-drm_buddy_block_order(struct drm_buddy_block *block)
-{
- return block->header & DRM_BUDDY_HEADER_ORDER;
-}
-
-static inline unsigned int
-drm_buddy_block_state(struct drm_buddy_block *block)
-{
- return block->header & DRM_BUDDY_HEADER_STATE;
-}
-
-static inline bool
-drm_buddy_block_is_allocated(struct drm_buddy_block *block)
-{
- return drm_buddy_block_state(block) == DRM_BUDDY_ALLOCATED;
-}
-
-static inline bool
-drm_buddy_block_is_clear(struct drm_buddy_block *block)
-{
- return block->header & DRM_BUDDY_HEADER_CLEAR;
-}
-
-static inline bool
-drm_buddy_block_is_free(struct drm_buddy_block *block)
-{
- return drm_buddy_block_state(block) == DRM_BUDDY_FREE;
-}
-
-static inline bool
-drm_buddy_block_is_split(struct drm_buddy_block *block)
-{
- return drm_buddy_block_state(block) == DRM_BUDDY_SPLIT;
-}
-
-static inline u64
-drm_buddy_block_size(struct drm_buddy *mm,
- struct drm_buddy_block *block)
-{
- return mm->chunk_size << drm_buddy_block_order(block);
-}
-
-int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size);
-
-void drm_buddy_fini(struct drm_buddy *mm);
-
-struct drm_buddy_block *
-drm_get_buddy(struct drm_buddy_block *block);
-
-int drm_buddy_alloc_blocks(struct drm_buddy *mm,
- u64 start, u64 end, u64 size,
- u64 min_page_size,
- struct list_head *blocks,
- unsigned long flags);
-
-int drm_buddy_block_trim(struct drm_buddy *mm,
- u64 *start,
- u64 new_size,
- struct list_head *blocks);
-
-void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear);
-
-void drm_buddy_free_block(struct drm_buddy *mm, struct drm_buddy_block *block);
-
-void drm_buddy_free_list(struct drm_buddy *mm,
- struct list_head *objects,
- unsigned int flags);
-
-void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p);
-void drm_buddy_block_print(struct drm_buddy *mm,
- struct drm_buddy_block *block,
+/* DRM-specific GPU Buddy Allocator print helpers */
+void drm_buddy_print(struct gpu_buddy *mm, struct drm_printer *p);
+void drm_buddy_block_print(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block,
struct drm_printer *p);
#endif
--- /dev/null
+++ b/include/linux/gpu_buddy.h
@@ -0,0 +1,188 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#ifndef __GPU_BUDDY_H__
+#define __GPU_BUDDY_H__
+
+#include <linux/bitops.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/rbtree.h>
+
+#include <drm/drm_print.h>
+
+#define range_overflows(start, size, max) ({ \
+ typeof(start) start__ = (start); \
+ typeof(size) size__ = (size); \
+ typeof(max) max__ = (max); \
+ (void)(&start__ == &size__); \
+ (void)(&start__ == &max__); \
+ start__ >= max__ || size__ > max__ - start__; \
+})
+
+#define GPU_BUDDY_RANGE_ALLOCATION BIT(0)
+#define GPU_BUDDY_TOPDOWN_ALLOCATION BIT(1)
+#define GPU_BUDDY_CONTIGUOUS_ALLOCATION BIT(2)
+#define GPU_BUDDY_CLEAR_ALLOCATION BIT(3)
+#define GPU_BUDDY_CLEARED BIT(4)
+#define GPU_BUDDY_TRIM_DISABLE BIT(5)
+
+enum gpu_buddy_free_tree {
+ GPU_BUDDY_CLEAR_TREE = 0,
+ GPU_BUDDY_DIRTY_TREE,
+ GPU_BUDDY_MAX_FREE_TREES,
+};
+
+#define for_each_free_tree(tree) \
+ for ((tree) = 0; (tree) < GPU_BUDDY_MAX_FREE_TREES; (tree)++)
+
+struct gpu_buddy_block {
+#define GPU_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
+#define GPU_BUDDY_HEADER_STATE GENMASK_ULL(11, 10)
+#define GPU_BUDDY_ALLOCATED (1 << 10)
+#define GPU_BUDDY_FREE (2 << 10)
+#define GPU_BUDDY_SPLIT (3 << 10)
+#define GPU_BUDDY_HEADER_CLEAR GENMASK_ULL(9, 9)
+/* Free to be used, if needed in the future */
+#define GPU_BUDDY_HEADER_UNUSED GENMASK_ULL(8, 6)
+#define GPU_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0)
+ u64 header;
+
+ struct gpu_buddy_block *left;
+ struct gpu_buddy_block *right;
+ struct gpu_buddy_block *parent;
+
+ void *private; /* owned by creator */
+
+ /*
+ * While the block is allocated by the user through gpu_buddy_alloc*,
+ * the user has ownership of the link, for example to maintain within
+ * a list, if so desired. As soon as the block is freed with
+ * gpu_buddy_free* ownership is given back to the mm.
+ */
+ union {
+ struct rb_node rb;
+ struct list_head link;
+ };
+
+ struct list_head tmp_link;
+};
+
+/* Order-zero must be at least SZ_4K */
+#define GPU_BUDDY_MAX_ORDER (63 - 12)
+
+/*
+ * Binary Buddy System.
+ *
+ * Locking should be handled by the user, a simple mutex around
+ * gpu_buddy_alloc* and gpu_buddy_free* should suffice.
+ */
+struct gpu_buddy {
+ /* Maintain a free list for each order. */
+ struct rb_root **free_trees;
+
+ /*
+ * Maintain explicit binary tree(s) to track the allocation of the
+ * address space. This gives us a simple way of finding a buddy block
+ * and performing the potentially recursive merge step when freeing a
+ * block. Nodes are either allocated or free, in which case they will
+ * also exist on the respective free list.
+ */
+ struct gpu_buddy_block **roots;
+
+ /*
+ * Anything from here is public, and remains static for the lifetime of
+ * the mm. Everything above is considered do-not-touch.
+ */
+ unsigned int n_roots;
+ unsigned int max_order;
+
+ /* Must be at least SZ_4K */
+ u64 chunk_size;
+ u64 size;
+ u64 avail;
+ u64 clear_avail;
+};
+
+static inline u64
+gpu_buddy_block_offset(const struct gpu_buddy_block *block)
+{
+ return block->header & GPU_BUDDY_HEADER_OFFSET;
+}
+
+static inline unsigned int
+gpu_buddy_block_order(struct gpu_buddy_block *block)
+{
+ return block->header & GPU_BUDDY_HEADER_ORDER;
+}
+
+static inline unsigned int
+gpu_buddy_block_state(struct gpu_buddy_block *block)
+{
+ return block->header & GPU_BUDDY_HEADER_STATE;
+}
+
+static inline bool
+gpu_buddy_block_is_allocated(struct gpu_buddy_block *block)
+{
+ return gpu_buddy_block_state(block) == GPU_BUDDY_ALLOCATED;
+}
+
+static inline bool
+gpu_buddy_block_is_clear(struct gpu_buddy_block *block)
+{
+ return block->header & GPU_BUDDY_HEADER_CLEAR;
+}
+
+static inline bool
+gpu_buddy_block_is_free(struct gpu_buddy_block *block)
+{
+ return gpu_buddy_block_state(block) == GPU_BUDDY_FREE;
+}
+
+static inline bool
+gpu_buddy_block_is_split(struct gpu_buddy_block *block)
+{
+ return gpu_buddy_block_state(block) == GPU_BUDDY_SPLIT;
+}
+
+static inline u64
+gpu_buddy_block_size(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block)
+{
+ return mm->chunk_size << gpu_buddy_block_order(block);
+}
+
+int gpu_buddy_init(struct gpu_buddy *mm, u64 size, u64 chunk_size);
+
+void gpu_buddy_fini(struct gpu_buddy *mm);
+
+struct gpu_buddy_block *
+gpu_get_buddy(struct gpu_buddy_block *block);
+
+int gpu_buddy_alloc_blocks(struct gpu_buddy *mm,
+ u64 start, u64 end, u64 size,
+ u64 min_page_size,
+ struct list_head *blocks,
+ unsigned long flags);
+
+int gpu_buddy_block_trim(struct gpu_buddy *mm,
+ u64 *start,
+ u64 new_size,
+ struct list_head *blocks);
+
+void gpu_buddy_reset_clear(struct gpu_buddy *mm, bool is_clear);
+
+void gpu_buddy_free_block(struct gpu_buddy *mm, struct gpu_buddy_block *block);
+
+void gpu_buddy_free_list(struct gpu_buddy *mm,
+ struct list_head *objects,
+ unsigned int flags);
+
+void gpu_buddy_print(struct gpu_buddy *mm);
+void gpu_buddy_block_print(struct gpu_buddy *mm,
+ struct gpu_buddy_block *block);
+#endif
next prev parent reply other threads:[~2026-07-30 15:51 UTC|newest]
Thread overview: 607+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-30 14:06 [PATCH 6.12 000/602] 6.12.101-rc1 review Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 001/602] platform/x86/intel-uncore-freq: Fix current_freq_khz after CPU hotplug Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 002/602] net: airoha: Move airoha_eth driver in a dedicated folder Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 003/602] net: airoha: Fix skb->priority underflow in airoha_dev_select_queue() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 004/602] bpf: Fix ld_{abs,ind} failure path analysis in subprogs Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 005/602] selftests/bpf: Add tests for ld_{abs,ind} failure path " Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 006/602] netfilter: nft_counter: serialize reset with spinlock Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 007/602] netfilter: nft_quota: use atomic64_xchg for reset Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 008/602] netfilter: nf_tables: revert commit_mutex usage in reset path Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 009/602] drm/virtio: fix deadlock in display_info_cb by removing hotplug from dequeue worker Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 010/602] fs/proc/task_mmu: fix make_uffd_wp_huge_pte() prot-update race Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 011/602] seqlock: Cure some more scoped_seqlock() optimization fails Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 012/602] seqlock: Allow KASAN to fail optimizing Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 013/602] seqlock: Allow UBSAN_ALIGNMENT " Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 014/602] KVM: x86: Check for invalid/obsolete root *after* making MMU pages available Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 015/602] KVM: x86: Only reset TSC Deadline Timer in apic_timer_expired on KVM_RUN Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 016/602] KVM: nVMX: Hide shadow VMCS right after VMCLEAR Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 017/602] KVM: x86/mmu: Fix use-after-free on vendor module reload Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 018/602] can: bcm: add locking when updating filter and timer values Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 019/602] can: bcm: fix CAN frame rx/tx statistics Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 020/602] can: bcm: extend bcm_tx_lock usage for data and timer updates Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 021/602] can: bcm: validate frame length in bcm_rx_setup() for RTR replies Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 022/602] can: bcm: add missing device refcount for CAN filter removal Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 023/602] can: bcm: fix stale rx/tx ops after device removal Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 024/602] can: bcm: fix data race on rx_stamp/rx_ifindex in bcm_rx_handler() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 025/602] can: bcm: track a single source interface for ANYDEV timeout/throttle ops Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 026/602] can: isotp: fix use-after-free race with concurrent NETDEV_UNREGISTER Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.12 027/602] can: isotp: serialize TX state transitions under so->rx_lock Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 028/602] dmaengine: sh: rz-dmac: Move interrupt request after everything is set up Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 029/602] Revert "arm64: dts: ti: k3-am62a7-sk: Add bootph-all tag to vqmmc" Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 030/602] gpu: host1x: Fix use-after-free in host1x_bo_clear_cached_mappings Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 031/602] crypto: tegra - Dont touch bo refcount in host1x bo pin/unpin Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 032/602] xprtrdma: Clear receive-side ownership pointers on release Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 033/602] Input: ims-pcu - fix heap-buffer-overflow in ims_pcu_process_data() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 034/602] Input: ims-pcu - fix logic error in packet reset Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 035/602] soc: qcom: ice: Allow explicit votes on iface clock for ICE Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 036/602] arm64: tegra: Fix CPU compatible string to cortex-a78ae on Tegra234 Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 037/602] firmware: arm_ffa: Respect firmware advertised RX/TX buffer size limits Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 038/602] IB/mad: Drop unmatched RMPP responses before reassembly Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 039/602] mtd: mtdswap: remove debugfs stats file on teardown Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 040/602] mtd: nand: mtk-ecc: stop on ECC idle timeouts Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 041/602] btrfs: reject free space cache with more entries than pages Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 042/602] btrfs: fix root leak if its reloc root is unexpected in merge_reloc_roots() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 043/602] firmware: arm_ffa: Fix NULL dereference in ffa_partition_info_get() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 044/602] RDMA/cma: Fix hardware address comparison length in netevent callback Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 045/602] RDMA/umem: Add pinned revocable dmabuf import interface Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 046/602] RDMA/irdma: Prevent rereg_mr for non-mem regions Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 047/602] RDMA/erdma: initialize ret for empty receive WR lists Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 048/602] RDMA/hns: Fix potential integer overflow in mhop hem cleanup Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 049/602] RDMA/siw: publish QP after initialization Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 050/602] mtd: fix double free and WARN_ON in add_mtd_device() error paths Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 051/602] selftests/alsa: Fix memory leak in find_controls error path Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 052/602] RDMA/irdma: Prevent overflows in memory contiguity checks Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 053/602] xfrm6: clear dst.dev on error to avoid double netdev_put in xfrm6_fill_dst() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 054/602] xfrm: policy: preallocate inexact bins before xfrm_hash_rebuild reinsert Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 055/602] wifi: cfg80211: cancel sched scan results work on unregister Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 056/602] wifi: ipw2100: fix potential memory leak in ipw2100_pci_init_one() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 057/602] wifi: mac80211_hwsim: clamp virtio RX length before skb_put Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 058/602] wifi: mac80211: fix unsol_bcast_probe_resp double free on alloc failure Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 059/602] wifi: mac80211: fix fils_discovery " Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 060/602] wifi: libertas: fix memory leak in helper_firmware_cb() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 061/602] wifi: p54: validate RX frame length in p54_rx_eeprom_readback() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 062/602] wifi: cfg80211: pass net_device to .set_monitor_channel Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 063/602] wifi: cfg80211: define and use wiphy guard Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 064/602] wifi: cfg80211: convert pmsr_free_wk to wiphy_work to fix deadlock Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 065/602] wifi: nl80211: free RNR data on MBSSID mismatch Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 066/602] wifi: cfg80211: derive S1G beacon TSF from S1G fields Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 067/602] wifi: nl80211: validate nested MBSSID IE blobs Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 068/602] wifi: cfg80211: validate PMSR measurement type data Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 069/602] wifi: cfg80211: validate PMSR FTM preamble range Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 070/602] wifi: cfg80211: reject unsupported PMSR FTM location requests Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 071/602] wifi: mac80211: free AP_VLAN bc_buf SKBs outside IRQ lock Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 072/602] wifi: brcmfmac: initialize SDIO data work before cleanup Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 073/602] wifi: cfg80211: bound element ID read when checking non-inheritance Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 074/602] ASoC: meson: aiu: fifo-spdif: soft reset the S/PDIF datapath on start/stop Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 075/602] ASoC: amd: ps: fix wrong ACP version string in pci_request_regions() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 076/602] ASoC: cs42l43: Correct report for forced microphone jack Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 077/602] ASoC: tas2562: fix deprecated shut-down GPIO always cleared after lookup Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 078/602] firmware: arm_scmi: Rate-limit queue-full warnings in IRQ context Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 079/602] cpufreq: Make cpufreq_update_pressure() fall back to cpuinfo.max_freq Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 080/602] ppp: defer channel free to an RCU grace period to fix pppol2tp RX UAF Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 081/602] ipv4: fib: free fib_alias with kfree_rcu() on insert error path Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 082/602] net/iucv: take a reference on the socket found in afiucv_hs_rcv() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 083/602] udmabuf: Ensure to perform cache synchronisation in begin_cpu_udmabuf() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 084/602] scsi: core: wake eh reliably when using scsi_schedule_eh Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 085/602] ata: sata_dwc_460ex: enable SATA interrupts only after IRQ handler is registered Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 086/602] ata: sata_dwc_460ex: use platform_get_irq() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.12 087/602] ata: sata_dwc_460ex: fix clear_interrupt_bit() clearing all pending interrupts Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 088/602] ata: sata_dwc_460ex: fix infinite loop in NCQ tag completion bit-scanning Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 089/602] accel/ivpu: Fix wrong register read in LNL failure diagnostics Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 090/602] ALSA: usb-audio: Skip DSD quirk for Musical Fidelity M6s DAC Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 091/602] Bluetooth: qca: fix NVM tag length underflow in TLV parser Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 092/602] Bluetooth: MGMT: revalidate LOAD_CONN_PARAM queued update Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 093/602] Bluetooth: mgmt: fix locking in unpair_device/disconnect_sync Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 094/602] Bluetooth: mgmt: hold reference for hci_conn in mgmt_pending_cmds Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 095/602] Bluetooth: hci_qca: Clear memdump state on invalid dump size Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 096/602] smb/client: handle overlapping allocated ranges in fallocate Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 097/602] drm/i915/gt: use correct selftest config symbol Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 098/602] powerpc/85xx: Add fsl,ifc to common device ids Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 099/602] powerpc/time: Prepare to stop elapsing in dynticks-idle Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 100/602] powerpc/vtime: Initialize starttime at boot for native accounting Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 101/602] bpf, sockmap: Reject unhashed UDP sockets on sockmap update Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 102/602] s390/checksum: Fix csum_partial() without vector facility Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 103/602] riscv: hwprobe: Avoid uninitialized read in hwprobe_get_cpus() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 104/602] can: j1939: fix lockless local-destination check Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 105/602] drm/xe/wopcm: fix WOPCM size for LNL+ Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 106/602] smb: move some duplicate definitions to common/cifsglob.h Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 107/602] ksmbd: pin conn during async oplock break notification Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 108/602] ksmbd: validate compound request size before reading StructureSize2 Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 109/602] drm/i915/selftests: Fix GT PM sort comparators Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 110/602] net/sched: act_tunnel_key: Defer dst_release to RCU callback Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 111/602] sctp: fix auth_hmacs array size in struct sctp_cookie Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 112/602] mpls: fix NULL deref in mpls_valid_fib_dump_req() on CONFIG_INET=n Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 113/602] usb: core: sysfs: add lock to bos_descriptors_read() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 114/602] wifi: at76c50x-usb: avoid length underflow in at76_guess_freq() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 115/602] usb: core: port: Deattach Type-C connector on component unbind Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 116/602] USB: storage: add NO_ATA_1X quirk for Longmai USB Key Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 117/602] usb: chipidea: fix usage_count leak when autosuspend_delay is negative Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 118/602] usb: gadget: dummy_hcd: prevent fifo_req reuse during giveback Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 119/602] usb: gadget: f_midi: cancel pending IN work before freeing the midi object Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 120/602] usb: gadget: printer: fix infinite loop in printer_read() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 121/602] USB: gadget: snps-udc: fix device name leak on probe failure Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 122/602] USB: gadget: fsl-udc: " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 123/602] usb: gadget: f_ncm: validate datagram bounds in ncm_unwrap_ntb() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 124/602] usb: gadget: udc: bdc: free IRQ and drain func_wake_notify before teardown Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 125/602] usb: gadget: uvc: clamp SEND_RESPONSE length to the response buffer Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 126/602] USB: serial: ftdi_sio: add support for E+H FXA291 Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 127/602] USB: serial: io_edgeport: cap received transmit credits Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 128/602] USB: serial: keyspan_pda: fix data loss on receive throttling Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 129/602] USB: serial: option: add TDTECH MT5710-CN Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 130/602] crypto: rsa-pkcs1pad: Dont WARN on an empty digest Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 131/602] Revert "drm/amd/display: Add missing kdoc for ALLM parameters" Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 132/602] RISC-V: KVM: Serialize virtual interrupt pending state updates Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 133/602] usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 134/602] wifi: ath9k: hif_usb: dont dereference hif_dev after re-arming firmware request Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 135/602] wifi: ath11k: fix NULL pointer dereference in ath11k_hal_srng_access_begin Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 136/602] hwmon: (corsair-psu) Stop device IO before calling hid_hw_stop Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 137/602] hwmon: (corsair-cpro) " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 138/602] hwmon: (gigabyte_waterforce) " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 139/602] hwmon: (nzxt-smart2) " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 140/602] hwmon: (nzxt-kraken3) " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 141/602] watchdog: pretimeout: Fix UAF in watchdog_unregister_governor() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 142/602] wifi: ath11k: fix potential buffer underflow in ath11k_hal_rx_msdu_list_get() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 143/602] wifi: ath11k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 144/602] wifi: ath12k: " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 145/602] firewire: net: Fix fragmented datagram reassembly Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 146/602] wifi: ath6kl: fix OOB read from firmware num_msg in TX complete handler Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.12 147/602] wifi: ath6kl: fix OOB read from firmware IE lengths in connect event Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 148/602] wifi: carl9170: bound memcpy length in cmd callback to prevent OOB read Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 149/602] wifi: carl9170: fix OOB read from off-by-two in TX status handler Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 150/602] wifi: carl9170: fix buffer overflow in rx_stream failover path Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 151/602] btrfs: declare btrfs_ioctl_search_args_v2::buf as __u8 Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 152/602] btrfs: dont propagate EXTENT_FLAG_LOGGING to split extent maps Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 153/602] btrfs: free mapping node on duplicate reloc root insert Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 154/602] ASoC: tas2781: bound firmware description string parsing Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 155/602] ALSA: hda: cs35l41: Fix NULL pointer dereference in cs35l41_get_acpi_mute_state() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 156/602] ALSA: hda: cs35l41: validate and free ACPI mute object Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 157/602] ASoC: bt-sco: fix duplicate DAPM widget names for wideband DAI Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 158/602] ASoC: cs35l56: Dont use devres to unregister component Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 159/602] ASoC: cs35l56: Fix potential probe() deadlock Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 160/602] ASoC: cs35l56: Use complete_all() to signal init_completion Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 161/602] wifi: iwlwifi: mvm: validate SAR GEO response payload size Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 162/602] wifi: iwlwifi: mvm: fix read in wake packet notification handler Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 163/602] usb: atm: ueagle-atm: reject descriptors that confuse probe and disconnect Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 164/602] drivers/virt: pkvm: Fix end calculation in mmio_guard_ioremap_hook() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 165/602] hwmon: (asus-ec-sensors) fix looping over banks while reading from EC Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 166/602] hwmon: (asus-ec-sensors) fix EC read intervals Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 167/602] hwmon: (asus-ec-sensors) add missed handle for ENOMEM Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 168/602] smb: client: validate DFS referral PathConsumed Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 169/602] hwmon: occ: validate poll response sensor blocks Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 170/602] regulator: mt6358: use regmap helper to read fixed LDO calibration Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 171/602] Bluetooth: btusb: validate Realtek vendor event length Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 172/602] netlink: specs: rt-link: convert bridge port flag attributes to u8 Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 173/602] net/packet: avoid fanout hook re-registration after unregister Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 174/602] bonding: fix devconf_all NULL dereference when IPv6 is disabled Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 175/602] rds: drop incoming messages that cross network namespace boundaries Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 176/602] gtp: parse extension headers before reading inner protocol Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 177/602] dpaa2-switch: put MAC endpoint device on disconnect Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 178/602] dpaa2-eth: " Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 179/602] iommu/amd: Wait for completion instead of returning early in iommu_completion_wait() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 180/602] wifi: mac80211: tear down new links on vif update error path Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 181/602] nfp: Check resource mutex allocation Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 182/602] wan: wanxl: Only reset hardware after BAR mapping Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 183/602] wifi: mwifiex: bound uAP association event IEs to the event buffer Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 184/602] iommu/amd: Bound the early ACPI HID map Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 185/602] iommu/intel: Fix out-of-bounds memset in dmar_latency_disable() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 186/602] wifi: mac80211: recalculate TIM when a station enters power save Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 187/602] pds_core: reject component parameter in legacy firmware update Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 188/602] amd-xgbe: fix MAC_AUTO_SW handling in CL37 AN Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 189/602] net: txgbe: fix FDIR filter leak on remove Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 190/602] sctp: fix auth_chunk_list capacity check in sctp_auth_ep_add_chunkid Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 191/602] pds_core: fix deadlock between reset thread and remove Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 192/602] pds_core: fix use-after-free on workqueue during remove Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 193/602] pds_core: yield the CPU while waiting for the adminq to drain Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 194/602] pds_core: order completion reads after the ownership check Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 195/602] pds_core: fix auxiliary device add/del races Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 196/602] pds_core: check for workqueue allocation failure Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 197/602] sctp: validate stream count in sctp_process_strreset_inreq() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 198/602] net: mctp i3c: clean up notifier and buses if driver register fails Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 199/602] tls: device: push pending open record on splice EOF Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 200/602] selftests: af_unix: add USER_NS config Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 201/602] selftests: openvswitch: add config file Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 202/602] gtp: check skb_pull_data() return in gtp1u_send_echo_resp() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 203/602] nexthop: initialize extack in nh_res_bucket_migrate() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 204/602] tipc: fix infinite loop in __tipc_nl_compat_dumpit Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 205/602] wifi: mt76: mt7925: guard link STA in decap offload Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 206/602] wifi: mt76: mt7915: guard HE capability lookups Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.12 207/602] wifi: mt76: connac: fix possible NULL-pointer deref in mt76_connac_mcu_uni_bss_he_tlv() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 208/602] wifi: mt76: mt7925: fix possible NULL-pointer deref in mt7925_mcu_bss_he_tlv() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 209/602] wifi: mt76: mt7996: check pointer returned by mt76_connac_get_he_phy_cap() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 210/602] wifi: mt76: mt7925: fix crash in reset link replay Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 211/602] wifi: mt76: mt7996: fix possible NULL-pointer deref in mt7996_mcu_sta_bfer_eht() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 212/602] wifi: brcmfmac: fix 802.1X-SHA256 call trace warning Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 213/602] ovl: fix trusted xattr escape prefix matching Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 214/602] amt: re-read skb header pointers after every pull Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 215/602] amt: make the head writable before rewriting the L2 header Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 216/602] net: bridge: vlan: fix vlan range dumps starting with pvid Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 217/602] net: hsr: fix memory leak on slave unregistration by removing synced VLANs Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 218/602] net: dpaa: fix mode setting Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 219/602] sctp: auth: verify auth requirement when auth_chunk is NULL Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 220/602] vmxnet3: fix BUG_ON in vmxnet3_get_hdr_len() for Geneve packets Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 221/602] iomap: correct the range of a partial dirty clear Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 222/602] tipc: fix u16 MTU truncation in media and bearer MTU validation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 223/602] drm/tests: shmem: Set DMA mask to 64-bit in drm_gem_shmem Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 224/602] net: stmmac: fix l3l4 filter rejecting unsupported offload requests Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 225/602] net: stmmac: reset residual action in L3L4 filters on delete Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 226/602] net: stmmac: enable the MAC on link up for all supported speeds Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 227/602] net: gre: fix lltx regression for GRE tunnels with SEQ/CSUM Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 228/602] octeontx2-vf: set TC flower flag on MCAM entry allocation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 229/602] ipv4: icmp: fill flow parameters in icmp_route_lookup decoy lookup Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 230/602] ppp: use IFF_NO_QUEUE in virtual interfaces Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 231/602] ppp: convert to percpu netstats Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 232/602] ppp: enable TX scatter-gather Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 233/602] ppp: annotate data races in ppp_generic Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 234/602] hinic: remove unused ethtool RSS user configuration buffers Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 235/602] net: qrtr: restrict socket creation to the initial network namespace Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 236/602] dpll: add clock quality level attribute and op Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 237/602] net/mlx5: DPLL, Add clock quality level op implementation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 238/602] net/mlx5: Remove newline at the end of a netlink error message Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 239/602] net/mlx5: Refactor EEPROM query error handling to return status separately Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 240/602] net/mlx5: Fix MCIA register buffer overflow on 32 dword reads Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 241/602] net/mlx5: E-Switch, fix zero num_dest in prio_tag egress vlan rule Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 242/602] net/mlx5e: Report zero bandwidth for non-ETS traffic classes Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 243/602] net/mlx5e: Reject unsupported CB Shaper TSA in ETS validation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 244/602] octeontx2-pf: tc: fix egress ratelimiting Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 245/602] net: ipv6: fix dif and sdif mismatch in raw6_icmp_error Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 246/602] ice: allow creating VFs when !CONFIG_ICE_SWITCHDEV Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 247/602] ice: fix LAG recipe to profile association Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 248/602] rds: tcp: unregister sysctl before tearing down listen socket Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 249/602] net: airoha: fix ETS channel derivation in airoha_tc_setup_qdisc_ets() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 250/602] bpf, sockmap: Fix cork use-after-free in tcp_bpf_sendmsg() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 251/602] drm: renesas: rzg2l_mipi_dsi: Increase reset deassertion delay Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 252/602] drm/rockchip: cdn-dp: add missing check in cdn_dp_config_video() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 253/602] drm/imagination: Count paired job fence as dependency in prepare_job() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 254/602] drm/bridge: cdns-dsi: Replace deprecated UNIVERSAL_DEV_PM_OPS() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 255/602] drm/dp/mst: fix OOB reads in remote DPCD/I2C sideband reply parsers Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 256/602] drm/dp/mst: fix buffer overflows in sideband chunk accumulation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 257/602] drm/imagination: Fit paired fragment job in the correct CCCB Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 258/602] drm/dp/mst: fix OOB reads on 2-byte fields in sideband reply parsers Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 259/602] drm/amdgpu/uvd: Fix forcing MSG, FB BOs into VCPU segment when it isnt at 0 (v2) Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 260/602] drm/amdgpu/uvd: Place VCPU BO only in VRAM for UVD 4.x and older Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 261/602] drm/amdgpu: Fix amdgpu_bo_move() when old_mem and new_mem are both GTT Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 262/602] drm/amdgpu: validate CP_GFX_SHADOW chunk size in CS pass1 Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 263/602] drm/nouveau: fix reversed error cleanup order in ucopy functions Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 264/602] drm/displayid: fix Tiled Display Topology ID size Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 265/602] drm/i915/gem: Add missing nospec on parallel submit slot Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 266/602] drm/nouveau/acr: fix missing nvkm_done() in error path of nvkm_acr_oneinit() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.12 267/602] drm/radeon: fix r100_copy_blit for large BOs Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 268/602] drm/xe: Fix PTE index in xe_vm_populate_pgtable() for chunked binds Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 269/602] drm/imagination: Fix double call to drm_sched_entity_fini() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 270/602] drm/imagination: Fix user array stride in pvr_set_uobj_array() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 271/602] drm/imagination: fix error checking of pvr_vm_context_lookup() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 272/602] drm/imagination: acquire vm_ctx->lock before mapping memory to GPU VM Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 273/602] drm/amdkfd: Use kvcalloc to allocate arrays Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 274/602] drm/amdkfd: Check bounds in allocate_event_notification_slot Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 275/602] drm/amdkfd: fix 32-bit overflow in CWSR total size calculation Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 276/602] drm/amd/display: Handle struct drm_plane_state.ignore_damage_clips Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 277/602] drm/amd/display: detect_link_and_local_sink: DP alt mode timeout path leaks prev_sink reference Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 278/602] drm/virtio: bound EDID block reads to the response buffer Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 279/602] drm/amdgpu/sdma7.0: replace BUG_ON() with WARN_ON() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 280/602] drm/amdgpu/sdma6.0: " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 281/602] drm/amdgpu/sdma5.2: " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 282/602] drm/amdgpu/sdma5.0: " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 283/602] drm/i915: Return NULL on error in active_instance Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 284/602] drm/i915/bios: range check LFP Data Block panel_type2 Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 285/602] drm/amdgpu: fix lifetime issue of amdgpu_vm_get_task_info_pasid() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 286/602] drm/i915/gem: Do not leak siblings[] on proto context error Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 287/602] drm/i915/gem: Fix NULL deref in I915_CONTEXT_PARAM_SSEU Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 288/602] drm/amd/pm: fix smu14 power limit range calculation Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 289/602] drm/gfx10: Program DB_RING_CONTROL Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 290/602] drm/panthor: return error on truncated firmware Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 291/602] drm/amdgpu: Fix VFCT bus number matching with soft filter Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 292/602] drm/amd/pm/ci: Dont disable MCLK DPM on Bonaire 0x6658 (R7 260X) Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 293/602] drm/amd/display: set new_stream to NULL after release Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 294/602] drm/amd/display: dce100: skip non-DP stream encoders for DP MST Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 295/602] drm/amdgpu: Disable PCIe dynamic speed switching on Ryzen Pinnacle Ridge Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 296/602] drm/amdgpu: fix bo->pin leaking in amdgpu_bo_create_reserved Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 297/602] drm/vmwgfx: Validate vmw_surface_metadata::array_size Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 298/602] drm/vc4: Prevent shader BO mappings from becoming writable Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 299/602] media: airspy: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 300/602] media: aspeed: fix missing of_reserved_mem_device_release() on probe failure Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 301/602] media: cec: seco: unregister adapter on IR " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 302/602] media: cedrus: clean up media device on " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 303/602] media: cedrus: Fix missing cleanup in error path Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 304/602] media: cedrus: skip invalid H.264 reference list entries Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 305/602] media: chips-media: wave5: Move src_buf Removal to finish_encode Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 306/602] media: cx231xx: fix devres lifetime Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 307/602] media: cx23885: add ioremap return check and cleanup Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 308/602] media: i2c: alvium: fix critical pointer access in alvium_ctrl_init Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 309/602] media: intel/ipu6: Improve DWC PHY HSFREQRANGE band selection for overlapping ranges Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 310/602] media: marvell-cam: fix missing pci_disable_device() on remove Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 311/602] media: meson: vdec: Fix memory leak in error path of vdec_open Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 312/602] media: msi2500: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 313/602] media: nuvoton: npcm-video: fix error handling in npcm_video_init() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 314/602] media: nuvoton: npcm-video: fix memory leaks in probe and remove Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 315/602] media: nxp: imx8-isi: Add missing v4l2_subdev_cleanup() in crossbar and pipe Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 316/602] media: nxp: imx8-isi: Clean up already-initialized pipes on probe failure Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 317/602] media: nxp: imx8-isi: Fix missing v4l2_subdev_cleanup() in pipe init error path Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 318/602] media: nxp: imx8-isi: Fix potential out-of-bounds issues Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 319/602] media: nxp: imx8-isi: Fix scale factor calculation for hardware rounding Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 320/602] media: pci: dm1105: Free allocated workqueue Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 321/602] media: pwc: Drain fill_buf on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 322/602] media: pwc: Return queued buffers " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 323/602] media: qcom: camss: Fix RDI streaming for CSID GEN2 Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 324/602] media: radio-si476x: Unregister v4l2_device on probe failure Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 325/602] media: rtl2832: fix use-after-free in rtl2832_remove() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 326/602] media: rtl2832_sdr: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.12 327/602] media: saa7134: Fix a possible memory leak in saa7134_video_init1 Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 328/602] media: stm32: dcmi: unregister notifier on probe failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 329/602] media: sun4i-csi: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 330/602] media: tegra-video: vi: fix invalid u32 return value in format lookup Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 331/602] media: ti: vpe: unwind v4l2 device registration on probe error Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 332/602] media: v4l2-ctrls-request: add NULL check in v4l2_ctrl_request_complete() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 333/602] media: v4l2-ctrls: validate HEVC active reference counts Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 334/602] media: v4l2-fwnode: Fix subdev owner overwritten in v4l2_async_register_subdev_sensor() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 335/602] media: v4l2-subdev: Fail {enable,disable}_streams and s_streaming nicely Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 336/602] media: vb2: use ssize_t for vb2_read/vb2_write Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 337/602] media: vidtv: fix reference leak on failed device registration Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 338/602] media: vimc: " Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 339/602] media: vivid: add vivid_update_reduced_fps() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 340/602] media: vivid: check for vb2_is_busy() when toggling caps Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 341/602] media: vivid: fix cleanup bugs in vivid_init() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 342/602] media: vpif_capture: fix OF node reference imbalance Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 343/602] ALSA: seq: close a re-opened queue timer in the destructor Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 344/602] ALSA: timer: drain a slaves callback before its master detaches it Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 345/602] ALSA: timer: dont re-enter an instance callback that is still running Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 346/602] wifi: ath6kl: fix OOB access from firmware ADDBA window size Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 347/602] wifi: mwifiex: fix NULL dereference when the AP has HT-cap but no HT-oper Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 348/602] wifi: wilc1000: validate assoc response length before subtracting header Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 349/602] wifi: mt76: mt7615: drop TXRX_NOTIFY on non-mmio buses Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 350/602] wifi: mt76: mt7921: " Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 351/602] wifi: mt76: mt7925: " Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 352/602] wifi: brcmfmac: make release_scratchbuffers idempotent Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 353/602] staging: rtl8723bs: fix OOB reads in rtw_get_wps_ie() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 354/602] staging: rtl8723bs: fix inverted HT40 secondary channel offset Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 355/602] Bluetooth: hci_sync: Protect UUID list traversal Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 356/602] Bluetooth: RFCOMM: Fix session UAF in set_termios Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 357/602] exec: fix unsigned loop counter wrap in transfer_args_to_stack() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 358/602] binfmt_misc: set have_execfd only once the interpreter is opened Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 359/602] platform/loongarch: laptop: Explicitly reset bl_powered state when suspend Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 360/602] rust: allow `clippy::unwrap_or_default` globally Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 361/602] objtool/rust: add one more `noreturn` Rust function for Rust 1.99.0 Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 362/602] LoongArch: Fix oops during single-step debugging Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 363/602] LoongArch: Move jump_label_init() before parse_early_param() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 364/602] LoongArch: Retrieve CPU package ID from PPTT when available Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 365/602] cdrom: fix stack out-of-bounds read in CDROMVOLCTRL Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 366/602] firmware: stratix10-svc: fix memory leaks and list corruption bugs Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 367/602] x86/boot/compressed: Disable jump tables Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 368/602] comedi: comedi_parport: deal with premature interrupt Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 369/602] uio_hv_generic: Bind to FCopy device by default Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 370/602] serial: sc16is7xx: implement gpio get_direction() callback Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 371/602] serial: 8250_mid: Fix NULL function pointer dereference on DNV/ICX-D/SNR platforms Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 372/602] mei: bus: access mei_device under device_lock on cleanup Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 373/602] intel_th: fix MSC output device reference leak Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 374/602] misc: nsm: only unlock nsm_dev on post-lock error paths Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 375/602] misc: nsm: pin the module while the device is open Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 376/602] tracing: Fix mmiotrace possible NULL dereferencing of hiter->dev Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 377/602] tracing: Fix resource leak on mmiotrace trace_pipe close Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 378/602] tracing/eprobe: Fix exact system name matching in eprobe_dyn_event_match() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 379/602] tracing/probes: Avoid temporary buffer truncation in trace_probe_match_command_args() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 380/602] tracing/probes: Fix potential underflow in LEN_OR_ZERO macro Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 381/602] tracing/probes: Prevent out-of-bounds write in __trace_probe_log_err() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 382/602] arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 383/602] Revert "arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates" Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 384/602] mptcp: decrement subflows counter on failed passive join Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 385/602] mptcp: only set DATA_FIN when a mapping is present Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 386/602] sctp: dont free the ASCONFs own transport in DEL-IP processing Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.12 387/602] sctp: avoid auth_enable sysctl UAF during netns teardown Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 388/602] sctp: close UDP tunnel sockets " Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 389/602] ceph: add owner/capability checks for CEPH_IOC_SET_LAYOUT* Greg Kroah-Hartman
2026-07-30 17:40 ` Ilya Dryomov
2026-07-30 14:13 ` [PATCH 6.12 390/602] ceph: fix pre-auth out-of-bounds read on snaptrace in ceph_handle_caps() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 391/602] ceph: fix refcount leak in ceph_readdir() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 392/602] libceph: bound get_version reply decode to front len Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 393/602] libceph: Fix multiplication overflow in decode_new_up_state_weight() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 394/602] libceph: guard missing CRUSH type name lookup Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 395/602] libceph: refresh auth->authorizer_buf{,_len} after authorizer update Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 396/602] libceph: Reject monmaps advertising zero monitors Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 397/602] libceph: reject zero bucket types in crush_decode Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 398/602] libceph: remove debugfs files before client teardown Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 399/602] amt: fix use-after-free in AMT delayed works Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 400/602] ASoC: fsl_sai: Fix spurious BCLK on resume by clearing BYP Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 401/602] binfmt_elf_fdpic: only honour the first PT_INTERP Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 402/602] fs: preserve ACL_DONT_CACHE state in forget_cached_acl() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 403/602] fscrypt: Add missing superblock check in find_or_insert_direct_key() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 404/602] ftrace: Add global mutex to serialize trace_parser access Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 405/602] iomap: fix out-of-bounds bitmap_set() with zero-length range Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 406/602] iommu/vt-d: Disallow SVA if page walk is not coherent Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 407/602] phonet: pep: fix use-after-free in pep_get_sb() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 408/602] vxlan: require CAP_NET_ADMIN in the device netns for changelink Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 409/602] net: slip: serialize receive against buffer reallocation Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 410/602] geneve: require CAP_NET_ADMIN in the device netns for changelink Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 411/602] net/af_iucv: fix NULL deref in afiucv_hs_callback_syn() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 412/602] net/iucv: fix use-after-free of a severed iucv_path Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 413/602] net/mlx5e: Use sender devcom for MPV master-up Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 414/602] net/x25: fix use-after-free in x25_kill_by_neigh() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 415/602] net: gro: fix double aggregation of flush-marked skbs Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 416/602] net: hip04: fix RX buffer leak on build_skb failure Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 417/602] proc: Fix broken error paths for namespace links Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 418/602] ice: fix PTP Call Trace during PTP release Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 419/602] selftests/ftrace: Reset triggers at top level before instance loop Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 420/602] rbd: Reset positive result codes to zero in object map update path Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 421/602] ksmbd: defer destroy_previous_session() until after NTLM authentication Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 422/602] ice: reject out-of-range ptype in ice_parser_profile_init Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 423/602] ice: use READ_ONCE() to access cached PHC time Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 424/602] ila: reload IPv6 header after pskb_may_pull in checksum adjust Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 425/602] mac802154: hold an interface reference across the scan worker Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 426/602] mac802154: llsec: reject frames shorter than the authentication tag Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 427/602] mctp: serial: handle zero-length frames to prevent rx buffer overflow Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 428/602] openvswitch: fix GSO userspace truncation underflow Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 429/602] pppoe: reload header pointer after dev_hard_header() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 430/602] rtase: Workaround for TX hang caused by hardware packet parsing Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 431/602] tcp: initialize standalone TCP-AO response padding Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 432/602] tipc: clear sock->sk on the failed-insert path in tipc_sk_create() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 433/602] vsock/virtio: collapse receive queue under memory pressure Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 434/602] vxlan: mdb: Fix source list corruption on a failed replace Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 435/602] drm/amd/pm: fix amdgpu_pm_info power display units Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 436/602] drm/amd/pm: make pp_features read-only when scpm is enabled Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 437/602] drm/amdgpu/gfx10: replace BUG_ON() with WARN_ON() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 438/602] drm/amdgpu/gfx11: " Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 439/602] drm/amdgpu/gfx12: " Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 440/602] drm/amdgpu/gfx8: drop unecessary BUG_ON() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 441/602] drm/amdgpu/gfx9.4.3: replace BUG_ON() with WARN_ON() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 442/602] drm/amdgpu/gfx9: " Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 443/602] drm/amdgpu/sdma4.4.2: " Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 444/602] drm/amdgpu/vce: fix integer overflow in image size Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 445/602] drm/amdgpu/vcn4: avoid rereading IB param length Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 446/602] drm/dp_mst: Handle torn-down topology gracefully in drm_dp_mst_topology_queue_probe() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.12 447/602] drm/amdgpu: fix division by zero with invalid uvd dimensions Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 448/602] drm/amdgpu: invoke pm_genpd_remove() before freeing genpd Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 449/602] drm/amdgpu: fix aperture mapping leak Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 450/602] drm/amd/pm: fix smu13 power limit range calculation Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 451/602] bpf: Fix same-register dst/src OOB read and pointer leak in sock_ops Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 452/602] net: qrtr: ns: Raise node count limit to 512 Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 453/602] ksmbd: validate num_subauth when copying ACE in set_ntacl_dacl Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 454/602] ksmbd: restore DACL size on check_add_overflow() to avoid malformed ACL Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 455/602] ksmbd: bound DACL dedup walk to copied ACEs Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 456/602] ksmbd: validate ACE size against SID sub-authorities Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 457/602] fscrypt: Avoid dynamic allocation in fscrypt_get_devices() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 458/602] drm/amd/display: Fix DTB DTO updates breaking live pixel rate sources Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 459/602] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 460/602] net: pcs: xpcs: fix SGMII state reading Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 461/602] gve: fix Rx queue stall on alloc failure Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 462/602] rust: allow `suspicious_runtime_symbol_definitions` lint for Rust >= 1.98 Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 463/602] mm/damon/core: validate ranges in damon_set_regions() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 464/602] mm/damon/core: disallow overlapping input ranges for damon_set_regions() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 465/602] iommufd: Reject invalid read count in iommufd_fault_fops_read() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 466/602] iommufd: Break the loop on failure " Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 467/602] iommufd: Avoid partial fault group delivery " Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 468/602] fpga: dfl-afu: validate DMA mapping length in afu_dma_map_region() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 469/602] i2c: davinci: Unregister cpufreq notifier on probe failure Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 470/602] VFS/audit: introduce kern_path_parent() for audit Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 471/602] audit: widen ino fields to u64 Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 472/602] audit: use unsigned int instead of unsigned Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 473/602] audit: fix recursive locking deadlock in audit_dupe_exe() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 474/602] i2c: i801: fix hardware state machine corruption in error path Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 475/602] ALSA: hda: conexant: Remove mic bias threshold override Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 476/602] ALSA: hda: Fix cached processing coefficient verbs Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 477/602] rxrpc: Pull out certain app callback funcs into an ops table Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 478/602] rxrpc: serialize kernel accept preallocation with socket teardown Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 479/602] xfs: factor out xfs_attr3_leaf_init Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 480/602] xfs: dont replace the wrong part of the cow fork Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 481/602] fbcon: Rename struct fbcon_ops to struct fbcon_par Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 482/602] fbcon: Use correct type for vc_resize() return value Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 483/602] rxrpc: Fix CPU time starvation in I/O thread Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 484/602] rxrpc: Dont need barrier for ->tx_bottom and ->acks_hard_ack Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 485/602] rxrpc: Use irq-disabling spinlocks between app and I/O thread Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 486/602] rxrpc: Fix notification vs call-release vs recvmsg Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 487/602] rxrpc: Fix socket notification race Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 488/602] tipc: restrict socket queue dumps in enqueue tracepoints Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 489/602] vduse: Use fixed 4KB bounce pages for non-4KB page size Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 490/602] vduse: remove unused vaddr parameter of vduse_domain_free_coherent Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 491/602] vduse: take out allocations from vduse_dev_alloc_coherent Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 492/602] VDUSE: avoid leaking information to userspace Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 493/602] octeontx2: Annotate mmio regions as __iomem Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 494/602] octeontx2-vf: clear stale mailbox IRQ state before request_irq() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 495/602] octeontx2-pf: " Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 496/602] arm64: dts: qcom: correct RBR opp entry Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 497/602] arm64: dts: qcom: hamoa: Fix OPP tables for all DisplayPort controllers Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 498/602] ASoC: mediatek: mt8192-afe-pcm: Simplify probe() with local dev variable Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 499/602] ASoC: mediatek: mt8192: Check runtime resume during probe Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 500/602] ASoC: mediatek: mt8183-afe-pcm: Shorten memif_data table using macros Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 501/602] ASoC: mediatek: mt8183-afe-pcm: Support >32 bit DMA addresses Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 502/602] ASoC: mediatek: mt8183-afe-pcm: use local `dev` pointer in driver callbacks Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 503/602] ASoC: mediatek: mt8183: Check runtime resume during probe Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 504/602] netfilter: nf_conntrack_sip: remove net variable shadowing Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 505/602] netfilter: nf_conntrack_sip: validate skb_dst() before accessing it Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 506/602] netfilter: bitwise: rename some boolean operation functions Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.12 507/602] netfilter: nf_tables: Remove unused nft_reduce_is_readonly() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 508/602] netfilter: nf_tables: remove register tracking infrastructure Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 509/602] netfilter: nft_fib: reject fib expression on the netdev egress hook Greg Kroah-Hartman
2026-07-30 14:15 ` Greg Kroah-Hartman [this message]
2026-07-30 14:15 ` [PATCH 6.12 511/602] gpu/buddy: bail out of try_harder when alignment cannot be honoured Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 512/602] NFSD: pass nfsd_file to nfsd_iter_read() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 513/602] sunrpc: allocate a separate bvec array for socket sends Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 514/602] SUNRPC: Add helpers to convert xdr_buf byte ranges to scatterlists Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 515/602] SUNRPC: Return an error from xdr_buf_to_bvec() on overflow Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 516/602] remoteproc: xlnx: Check remote core state Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 517/602] mm/hugetlb: fix hugetlb cgroup rsvd charge/uncharge mismatch Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 518/602] mm/sparse-vmemmap: fix vmemmap accounting underflow Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 519/602] landlock: Prepare to use credential instead of domain for fowner Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 520/602] landlock: Fix LANDLOCK_SCOPE_SIGNAL bypass on the SIGIO path Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 521/602] mm/mm_init: fix pageblock migratetype for ZONE_DEVICE compound pages Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 522/602] mtd: maps: vmu-flash: fix fault in unaligned fixup Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 523/602] mm: prepare to move subsection_map_init() to mm/sparse-vmemmap.c Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 524/602] mm/sparse-vmemmap: fix DAX vmemmap accounting with optimization Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 525/602] thunderbolt: Keep XDomain reference during the lifetime of a service Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 526/602] thunderbolt: Remove service debugfs entries during unregister Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 527/602] thunderbolt: Remove XDomain from the bus without holding tb->lock Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 528/602] thunderbolt: Prevent XDomain delayed work use-after-free on disconnect Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 529/602] dma: dw-edma: Fix build warning in dw_edma_pcie_probe() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 530/602] dmaengine: dw-edma: Fix confusing cleanup.h syntax Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 531/602] dmaengine: dw-edma-pcie: Reject devices without driver data Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 532/602] i2c: imx: separate atomic, dma and non-dma use case Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 533/602] i2c: imx: fix locked bus on SMBus block-read of 0 (atomic) Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 534/602] xfrm: Use nested-BH locking for nat_keepalive_sk_ipv[46] Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 535/602] xfrm: nat_keepalive: avoid double free on send error Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 536/602] tcp: defer md5sig_info kfree past RCU grace period in tcp_connect Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 537/602] tcp: Decrement tcp_md5_needed static branch Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 538/602] nvmet: Introduce nvmet_req_transfer_len() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 539/602] nvmet-auth: reject short AUTH_RECEIVE buffers Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 540/602] ovl: use linked upper dentry in copy-up tmpfile Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 541/602] bpf: Refactor {acquire,release}_reference_state Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 542/602] bpf: Refactor check_ctx_access() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 543/602] bpf: Reset register bounds before narrowing retval range in check_mem_access() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 544/602] block: add helper add_disk_final() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 545/602] block: remove redundant GD_NEED_PART_SCAN in add_disk_final() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 546/602] dm-integrity: fix leaking uninitialized kernel memory Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 547/602] cleanup: add a scoped version of CLASS() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 548/602] cleanup: fix scoped_class() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 549/602] cred: add kernel_cred() helper Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 550/602] cred: add scoped_with_kernel_creds() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 551/602] dm: avoid leaking the callers thread keyring via the table device file Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 552/602] wifi: libertas_tf: fix use-after-free in lbtf_free_adapter() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 553/602] mmc: vub300: fix use-after-free on disconnect Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 554/602] mmc: vub300: rename probe error labels Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 555/602] mmc: vub300: fix use-after-free on probe failure Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 556/602] locking/rt: Fix the incorrect RCU protection in rt_spin_unlock() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 557/602] net: mana: Validate the packet length reported by the NIC Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 558/602] net: ip6_tunnel: require CAP_NET_ADMIN in the device netns for changelink Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 559/602] gve: fix header buffer corruption with header-split and HW-GRO Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 560/602] gpio: mt7621: avoid corruption of shared interrupt trigger state Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 561/602] octeontx2-af: cn10k: restrict VF LMTLINE sharing to its own PF Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 562/602] bootconfig: move xbc_snprint_cmdline() to lib/bootconfig.c Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 563/602] bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 564/602] ipmi: fix refcount leak in i_ipmi_request() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 565/602] net/mlx5: HWS, Rearrange to prevent forward declaration Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 566/602] net/mlx5: HWS, fix matcher leak on resize target setup failure Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.12 567/602] octeontx2-pf: fix SQB pointer leak on init failure Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 568/602] ata: libata-core: Reject an invalid concurrent positioning ranges count Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 569/602] fs/resctrl: Fix double-add of pseudo-locked regions RMID to free list Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 570/602] net: macb: drop in-flight Tx SKBs on close Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 571/602] net: ipa: fix SMEM state handle leaks in SMP2P init Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 572/602] Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 573/602] Bluetooth: hci_core: Fix not accounting for BIS/CIS/PA links separately Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 574/602] afs: Improve server refcount/active count tracing Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 575/602] afs: Make afs_lookup_cell() take a trace note Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 576/602] afs: Drop the net parameter from afs_unuse_cell() Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 577/602] rxrpc: Allow the app to store private data on peer structs Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 578/602] afs: Use the per-peer app data provided by rxrpc Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 579/602] afs: Fix afs_server ref accounting Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 580/602] afs: Simplify cell record handling Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 581/602] afs: Fix dynamic lookup to fail on cell lookup failure Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 582/602] afs: Fix lack of locking around modifications of net->cells_dyn_ino Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 583/602] USB: gadget: Use str_enable_disable-like helpers Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 584/602] USB: gadget: fsl-udc: fix dev_printk() device Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 585/602] usb: musb: omap2430: clean up probe error handling Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 586/602] usb: musb: omap2430: Do not put borrowed of_node in probe Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 587/602] net/mlx5e: Fix NULL pointer dereference in ioctl module EEPROM query Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 588/602] gpu: Fix uninitialized buddy for built-in drivers Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 589/602] rxrpc: Disable IRQ, not BH, to take the lock for ->attend_link Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 590/602] rxrpc: Fix locking issues with the peer record hash Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 591/602] wifi: nl80211: fix nl80211_start_radar_detection return value Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 592/602] net: ethernet: Remove accidental duplication in Kconfig file Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 593/602] afs: Set vllist to NULL if addr parsing fails Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 594/602] dpll: fix clock quality level reporting Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 595/602] afs: Fix delayed allocation of a cells anonymous key Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 596/602] afs: handle CB.InitCallBackState3 requests without a server record Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 597/602] Bluetooth: hci_conn: Fix running bis_cleanup for hci_conn->type PA_LINK Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 598/602] Bluetooth: hci_conn: Fix not cleaning up Broadcaster/Broadcast Source Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 599/602] Bluetooth: hci_conn: Fix not cleaning up PA_LINK connections Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 600/602] Bluetooth: hci_conn: Fix memory leak in hci_le_big_terminate() Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 601/602] afs: Fix uninit var in afs_alloc_anon_key() Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.12 602/602] KVM: SVM: Bump asid_generation on CPU online to avoid ASID collision after hotplug Greg Kroah-Hartman
2026-07-30 17:37 ` [PATCH 6.12 000/602] 6.12.101-rc1 review Florian Fainelli
2026-07-30 18:47 ` Miguel Ojeda
2026-07-30 19:15 ` Peter Schneider
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260730141446.712461318@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=airlied@redhat.com \
--cc=joelagnelf@nvidia.com \
--cc=patches@lists.linux.dev \
--cc=sashal@kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox