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.18 622/675] gpu: Move DRM buddy allocator one level up (part two)
Date: Thu, 30 Jul 2026 16:15:52 +0200 [thread overview]
Message-ID: <20260730141458.342461372@linuxfoundation.org> (raw)
In-Reply-To: <20260730141445.110192266@linuxfoundation.org>
6.18-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
MAINTAINERS | 13
drivers/gpu/Kconfig | 13
drivers/gpu/Makefile | 3
drivers/gpu/buddy.c | 1322 +++++++++++++++++++
drivers/gpu/drm/Kconfig | 5
drivers/gpu/drm/Kconfig.debug | 1
drivers/gpu/drm/Makefile | 1
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 2
drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h | 12
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 79 -
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 20
drivers/gpu/drm/drm_buddy.c | 1278 ------------------
drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3
drivers/gpu/drm/i915/i915_scatterlist.c | 10
drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 59
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 | 44
drivers/gpu/drm/lib/drm_random.h | 28
drivers/gpu/drm/tests/Makefile | 1
drivers/gpu/drm/tests/drm_buddy_test.c | 788 -----------
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_svm.c | 12
drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 71 -
drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h | 4
drivers/gpu/tests/Makefile | 4
drivers/gpu/tests/gpu_buddy_test.c | 788 +++++++++++
drivers/gpu/tests/gpu_random.c | 44
drivers/gpu/tests/gpu_random.h | 28
drivers/video/Kconfig | 1
include/drm/drm_buddy.h | 165 --
include/linux/gpu_buddy.h | 177 ++
38 files changed, 2597 insertions(+), 2477 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} (66%)
rename drivers/gpu/{drm/lib/drm_random.c => tests/gpu_random.c} (59%)
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:
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8656,6 +8656,19 @@ T: git https://gitlab.freedesktop.org/dr
F: drivers/gpu/drm/ttm/
F: include/drm/ttm/
+GPU BUDDY ALLOCATOR
+M: Matthew Auld <matthew.auld@intel.com>
+M: Arun Pravin <arunpravin.paneerselvam@amd.com>
+R: Christian Koenig <christian.koenig@amd.com>
+L: dri-devel@lists.freedesktop.org
+S: Maintained
+T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+F: drivers/gpu/drm_buddy.c
+F: drivers/gpu/buddy.c
+F: drivers/gpu/tests/gpu_buddy_test.c
+F: include/linux/gpu_buddy.h
+F: include/drm/drm_buddy.h
+
DRM AUTOMATED TESTING
M: Helen Koike <helen.fornazier@gmail.com>
M: Vignesh Raman <vignesh.raman@collabora.com>
--- /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,7 +2,8 @@
# 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_NOVA_CORE) += nova-core/
+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
@@ -220,6 +220,7 @@ config DRM_GPUSVM
config DRM_BUDDY
tristate
depends on DRM
+ select GPU_BUDDY
help
A page based buddy allocator
@@ -416,10 +417,6 @@ config DRM_HYPERV
config DRM_PANEL_BACKLIGHT_QUIRKS
tristate
-config DRM_LIB_RANDOM
- bool
- default n
-
config DRM_PRIVACY_SCREEN
bool
default n
--- a/drivers/gpu/drm/Kconfig.debug
+++ b/drivers/gpu/drm/Kconfig.debug
@@ -69,7 +69,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 DRM_SYSFB_HELPER
select PRIME_NUMBERS
default KUNIT_ALL_TESTS
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -77,7 +77,6 @@ drm-$(CONFIG_DRM_CLIENT) += \
drm_client.o \
drm_client_event.o \
drm_client_modeset.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_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -5416,7 +5416,7 @@ int amdgpu_ras_add_critical_region(struc
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct amdgpu_vram_mgr_resource *vres;
struct ras_critical_region *region;
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
int ret = 0;
if (!bo || !bo->tbo.resource)
--- 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;
@@ -125,7 +125,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;
@@ -146,7 +146,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);
@@ -175,7 +175,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
@@ -25,6 +25,7 @@
#include <linux/dma-mapping.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/drm_drv.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);
@@ -403,7 +404,7 @@ int amdgpu_vram_mgr_query_address_block_
uint64_t address, struct amdgpu_vram_block_info *info)
{
struct amdgpu_vram_mgr_resource *vres;
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
u64 start, size;
int ret = -ENOENT;
@@ -450,8 +451,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;
@@ -493,17 +494,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)
@@ -516,7 +517,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);
@@ -536,7 +537,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,
@@ -545,7 +546,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);
@@ -566,7 +567,7 @@ static int amdgpu_vram_mgr_new(struct tt
list_add_tail(&vres->vres_node, &mgr->allocated_vres_list);
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;
@@ -576,7 +577,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);
}
@@ -614,7 +615,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);
@@ -637,8 +638,8 @@ 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);
@@ -649,7 +650,7 @@ static void amdgpu_vram_mgr_del(struct t
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);
@@ -688,7 +689,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++;
@@ -704,10 +705,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) {
@@ -792,10 +793,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);
}
@@ -815,7 +816,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) {
@@ -848,7 +849,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) {
@@ -877,7 +878,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",
@@ -930,7 +931,7 @@ int amdgpu_vram_mgr_init(struct amdgpu_d
mgr->default_page_size = PAGE_SIZE;
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;
@@ -965,11 +966,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;
@@ -57,19 +57,19 @@ struct amdgpu_vram_mgr_resource {
struct amdgpu_vres_task task;
};
-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 *
@@ -82,8 +82,8 @@ static inline void amdgpu_vram_mgr_set_c
{
struct amdgpu_vram_mgr_resource *ares = to_amdgpu_vram_mgr_resource(res);
- WARN_ON(ares->flags & DRM_BUDDY_CLEARED);
- ares->flags |= DRM_BUDDY_CLEARED;
+ WARN_ON(ares->flags & GPU_BUDDY_CLEARED);
+ ares->flags |= GPU_BUDDY_CLEARED;
}
int amdgpu_vram_mgr_query_address_block_info(struct amdgpu_vram_mgr *mgr,
--- a/drivers/gpu/drm/drm_buddy.c
+++ b/drivers/gpu/drm/drm_buddy.c
@@ -10,1250 +10,9 @@
#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);
-
- if (WARN_ON(!drm_buddy_block_is_free(mm->roots[i])))
- kunit_fail_current_test("buddy_fini() root");
-
- 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
@@ -1262,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);
}
@@ -1279,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;
@@ -1287,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;
@@ -1296,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++;
}
}
@@ -1314,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
@@ -5,9 +5,10 @@
#include <linux/shmem_fs.h>
+#include <linux/gpu_buddy.h>
+#include <drm/drm_print.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_tt.h>
-#include <drm/drm_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
@@ -5,18 +5,19 @@
#include <linux/slab.h>
+#include <linux/gpu_buddy.h>
+#include <drm/drm_buddy.h>
+#include <drm/drm_print.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_bo.h>
-#include <drm/drm_buddy.h>
-
#include "i915_ttm_buddy_manager.h"
#include "i915_gem.h"
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;
@@ -447,8 +447,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);
@@ -487,8 +487,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",
@@ -527,14 +527,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,44 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/bitops.h>
-#include <linux/export.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/prandom.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
@@ -7,7 +7,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_atomic_test.o \
drm_atomic_state_test.o \
drm_bridge_test.o \
- 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,788 +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;
- 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 from each
- * root, free as cleared and then call fini. This will ensure the multi-root
- * force merge during fini.
- */
- mm_size = (SZ_4K << max_order) + (SZ_4K << (max_order - 2));
-
- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
- KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order,
- 4 * ps, ps, &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc hit an error size=%lu\n", 4 * ps);
- drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order,
- 2 * ps, ps, &allocated,
- DRM_BUDDY_CLEAR_ALLOCATION),
- "buddy_alloc hit an error size=%lu\n", 2 * ps);
- drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED);
- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, SZ_4K << max_order, mm_size,
- ps, ps, &allocated,
- DRM_BUDDY_RANGE_ALLOCATION),
- "buddy_alloc hit an error size=%lu\n", ps);
- 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
@@ -30,7 +30,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;
@@ -46,14 +46,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);
@@ -66,7 +66,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);
@@ -78,10 +78,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);
@@ -105,7 +105,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);
@@ -141,7 +141,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
@@ -58,7 +58,7 @@ struct xe_res_cursor {
/** @dma_addr: Current element in a struct drm_pagemap_addr array */
const struct drm_pagemap_addr *dma_addr;
/** @mm: Buddy allocator for VRAM cursor */
- struct drm_buddy *mm;
+ struct gpu_buddy *mm;
/**
* @dma_start: DMA start address for the current segment.
* This may be different to @dma_addr.addr since elements in
@@ -69,7 +69,7 @@ struct xe_res_cursor {
u64 dma_seg_size;
};
-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;
@@ -104,30 +104,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;
@@ -259,7 +259,7 @@ static inline void xe_res_first_dma(cons
*/
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;
@@ -295,18 +295,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_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -689,7 +689,7 @@ static u64 block_offset_to_pfn(struct xe
return PHYS_PFN(offset + vr->hpa_base);
}
-static struct drm_buddy *vram_to_buddy(struct xe_vram_region *vram)
+static struct gpu_buddy *vram_to_buddy(struct xe_vram_region *vram)
{
return &vram->ttm.mm;
}
@@ -700,16 +700,16 @@ static int xe_svm_populate_devmem_pfn(st
struct xe_bo *bo = to_xe_bo(devmem_allocation);
struct ttm_resource *res = bo->ttm.resource;
struct list_head *blocks = &to_xe_ttm_vram_mgr_resource(res)->blocks;
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
int j = 0;
list_for_each_entry(block, blocks, link) {
struct xe_vram_region *vr = block->private;
- struct drm_buddy *buddy = vram_to_buddy(vr);
- u64 block_pfn = block_offset_to_pfn(vr, drm_buddy_block_offset(block));
+ struct gpu_buddy *buddy = vram_to_buddy(vr);
+ u64 block_pfn = block_offset_to_pfn(vr, gpu_buddy_block_offset(block));
int i;
- for (i = 0; i < drm_buddy_block_size(buddy, block) >> PAGE_SHIFT; ++i)
+ for (i = 0; i < gpu_buddy_block_size(buddy, block) >> PAGE_SHIFT; ++i)
pfn[j++] = block_pfn + i;
}
@@ -877,7 +877,7 @@ static int xe_drm_pagemap_populate_mm(st
struct dma_fence *pre_migrate_fence = NULL;
struct xe_device *xe = vr->xe;
struct device *dev = xe->drm.dev;
- struct drm_buddy_block *block;
+ struct gpu_buddy_block *block;
struct xe_validation_ctx vctx;
struct list_head *blocks;
struct drm_exec exec;
--- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
+++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
@@ -6,6 +6,7 @@
#include <drm/drm_managed.h>
#include <drm/drm_drv.h>
+#include <drm/drm_buddy.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
@@ -17,16 +18,16 @@
#include "xe_ttm_vram_mgr.h"
#include "xe_vram_types.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);
@@ -34,12 +35,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;
}
@@ -53,7 +54,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, min_page_size;
unsigned long lpfn;
int err;
@@ -80,10 +81,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;
@@ -119,27 +120,27 @@ static int xe_ttm_vram_mgr_new(struct tt
lpfn = max_t(unsigned long, place->fpfn + (size >> PAGE_SHIFT), lpfn);
}
- 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, size,
min_page_size, &vres->blocks, vres->flags);
if (err)
goto error_unlock;
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;
@@ -159,11 +160,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;
}
@@ -185,10 +186,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);
@@ -201,7 +202,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",
@@ -224,8 +225,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;
@@ -235,9 +236,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;
@@ -254,8 +255,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;
@@ -265,9 +266,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;
@@ -297,7 +298,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);
@@ -328,7 +329,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;
@@ -376,7 +377,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++;
@@ -393,10 +394,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>
/**
@@ -18,7 +18,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;
/** @visible_size: Proped size of the CPU visible portion */
u64 visible_size;
/** @visible_avail: CPU visible portion still unallocated */
--- /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,788 @@
+// 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 gpu_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 GPU 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 gpu_test_buddy_alloc_clear(struct kunit *test)
+{
+ unsigned long n_pages, total, i = 0;
+ 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 from each
+ * root, free as cleared and then call fini. This will ensure the multi-root
+ * force merge during fini.
+ */
+ mm_size = (SZ_4K << max_order) + (SZ_4K << (max_order - 2));
+
+ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps));
+ KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order,
+ 4 * ps, ps, &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc hit an error size=%lu\n", 4 * ps);
+ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order,
+ 2 * ps, ps, &allocated,
+ GPU_BUDDY_CLEAR_ALLOCATION),
+ "buddy_alloc hit an error size=%lu\n", 2 * ps);
+ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
+ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, SZ_4K << max_order, mm_size,
+ ps, ps, &allocated,
+ GPU_BUDDY_RANGE_ALLOCATION),
+ "buddy_alloc hit an error size=%lu\n", ps);
+ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED);
+ gpu_buddy_fini(&mm);
+}
+
+static void gpu_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 gpu_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 gpu_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 gpu_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 gpu_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 GPU buddy manager, with random_seed=0x%x\n",
+ random_seed);
+
+ return 0;
+}
+
+static struct kunit_case gpu_buddy_tests[] = {
+ KUNIT_CASE(gpu_test_buddy_alloc_limit),
+ KUNIT_CASE(gpu_test_buddy_alloc_optimistic),
+ KUNIT_CASE(gpu_test_buddy_alloc_pessimistic),
+ KUNIT_CASE(gpu_test_buddy_alloc_pathological),
+ KUNIT_CASE(gpu_test_buddy_alloc_contiguous),
+ KUNIT_CASE(gpu_test_buddy_alloc_clear),
+ KUNIT_CASE(gpu_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,44 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bitops.h>
+#include <linux/export.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/prandom.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"
source "drivers/gpu/nova-core/Kconfig"
--- a/include/drm/drm_buddy.h
+++ b/include/drm/drm_buddy.h
@@ -6,166 +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 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,177 @@
+/* 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>
+
+#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:24 UTC|newest]
Thread overview: 684+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-30 14:05 [PATCH 6.18 000/675] 6.18.42-rc1 review Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 001/675] platform/x86/intel-uncore-freq: Fix current_freq_khz after CPU hotplug Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 002/675] bpf: Fix ld_{abs,ind} failure path analysis in subprogs Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 003/675] selftests/bpf: Add tests for ld_{abs,ind} failure path " Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 004/675] netfilter: nft_counter: serialize reset with spinlock Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 005/675] netfilter: nft_quota: use atomic64_xchg for reset Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 006/675] netfilter: nf_tables: revert commit_mutex usage in reset path Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 007/675] drm/virtio: fix deadlock in display_info_cb by removing hotplug from dequeue worker Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 008/675] fs/proc/task_mmu: fix make_uffd_wp_huge_pte() prot-update race Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 009/675] seqlock: Cure some more scoped_seqlock() optimization fails Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 010/675] seqlock: Allow KASAN to fail optimizing Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 011/675] seqlock: Allow UBSAN_ALIGNMENT " Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 012/675] KVM: x86: Check for invalid/obsolete root *after* making MMU pages available Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 013/675] KVM: x86: Only reset TSC Deadline Timer in apic_timer_expired on KVM_RUN Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 014/675] KVM: nVMX: Hide shadow VMCS right after VMCLEAR Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 015/675] KVM: x86/mmu: Fix use-after-free on vendor module reload Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 016/675] can: bcm: add locking when updating filter and timer values Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 017/675] can: bcm: fix CAN frame rx/tx statistics Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 018/675] can: bcm: extend bcm_tx_lock usage for data and timer updates Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 019/675] can: bcm: validate frame length in bcm_rx_setup() for RTR replies Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 020/675] can: bcm: add missing device refcount for CAN filter removal Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 021/675] can: bcm: fix stale rx/tx ops after device removal Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 022/675] can: bcm: fix data race on rx_stamp/rx_ifindex in bcm_rx_handler() Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 023/675] can: bcm: track a single source interface for ANYDEV timeout/throttle ops Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 024/675] dmaengine: sh: rz-dmac: Move interrupt request after everything is set up Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 025/675] gpu: host1x: Fix use-after-free in host1x_bo_clear_cached_mappings Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 026/675] crypto: tegra - Dont touch bo refcount in host1x bo pin/unpin Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 027/675] xprtrdma: Clear receive-side ownership pointers on release Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 028/675] Input: ims-pcu - fix heap-buffer-overflow in ims_pcu_process_data() Greg Kroah-Hartman
2026-07-30 14:05 ` [PATCH 6.18 029/675] Input: ims-pcu - fix logic error in packet reset Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 030/675] fuse: fix writeback array overflow when max_pages is one Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 031/675] arm64: tegra: Remove fallback compatible for GPCDMA Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 032/675] arm64: tegra: Fix CPU compatible string to cortex-a78ae on Tegra234 Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 033/675] net: dropreason: add SKB_DROP_REASON_RECURSION_LIMIT Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 034/675] net: plumb drop reasons to __dev_queue_xmit() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 035/675] xfrm: propagate -EINPROGRESS from validate_xmit_xfrm() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 036/675] xfrm: fix stale skb->prev after async crypto steals a GSO segment Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 037/675] firmware: arm_ffa: Respect firmware advertised RX/TX buffer size limits Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 038/675] IB/mad: Drop unmatched RMPP responses before reassembly Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 039/675] mtd: mtdswap: remove debugfs stats file on teardown Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 040/675] mtd: nand: mtk-ecc: stop on ECC idle timeouts Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 041/675] btrfs: reject free space cache with more entries than pages Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 042/675] btrfs: fix root leak if its reloc root is unexpected in merge_reloc_roots() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 043/675] btrfs: use bool type for btrfs_path members used as booleans Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 044/675] btrfs: fallback to transaction csum tree on a commit root csum miss Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 045/675] firmware: arm_ffa: Fix NULL dereference in ffa_partition_info_get() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 046/675] sched/ext: Avoid null ptr traversal when ->put_prev_task() is called with NULL next Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 047/675] sched_ext: Dont warn on core-sched forced idle in put_prev_task_scx() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 048/675] xfrm: reject optional IPTFS templates in outbound policies Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 049/675] RDMA/cma: Fix hardware address comparison length in netevent callback Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 050/675] RDMA/umem: Add pinned revocable dmabuf import interface Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 051/675] RDMA/irdma: Prevent rereg_mr for non-mem regions Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 052/675] RDMA/irdma: Remove redundant legacy_mode checks Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 053/675] RDMA/irdma: Prevent user-triggered null deref on QP create Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 054/675] RDMA/erdma: initialize ret for empty receive WR lists Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 055/675] RDMA/mana_ib: initialize err for empty send " Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 056/675] RDMA/hns: Fix potential integer overflow in mhop hem cleanup Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 057/675] RDMA/siw: publish QP after initialization Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 058/675] mtd: fix double free and WARN_ON in add_mtd_device() error paths Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 059/675] selftests/alsa: Fix memory leak in find_controls error path Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 060/675] RDMA/irdma: Prevent overflows in memory contiguity checks Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 061/675] xfrm: clear mode callbacks after failed mode setup Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 062/675] xfrm: iptfs: propagate SKBFL_SHARED_FRAG in iptfs_skb_add_frags() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 063/675] xfrm6: clear dst.dev on error to avoid double netdev_put in xfrm6_fill_dst() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 064/675] xfrm: policy: preallocate inexact bins before xfrm_hash_rebuild reinsert Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 065/675] wifi: cfg80211: cancel sched scan results work on unregister Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 066/675] wifi: ipw2100: fix potential memory leak in ipw2100_pci_init_one() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 067/675] wifi: cfg80211: Fix an error handling path in cfg80211_wext_siwscan() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 068/675] wifi: mac80211_hwsim: clamp virtio RX length before skb_put Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 069/675] wifi: mac80211: fix unsol_bcast_probe_resp double free on alloc failure Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 070/675] wifi: mac80211: fix fils_discovery " Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 071/675] wifi: libertas: fix memory leak in helper_firmware_cb() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 072/675] wifi: mac80211: defer link RX stats percpu free to RCU Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 073/675] wifi: p54: validate RX frame length in p54_rx_eeprom_readback() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 074/675] wifi: cfg80211: convert pmsr_free_wk to wiphy_work to fix deadlock Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 075/675] wifi: nl80211: free RNR data on MBSSID mismatch Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 076/675] wifi: cfg80211: derive S1G beacon TSF from S1G fields Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 077/675] wifi: nl80211: validate nested MBSSID IE blobs Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 078/675] wifi: nl80211: constrain MBSSID TX link ID range Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 079/675] wifi: cfg80211: validate PMSR measurement type data Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 080/675] wifi: cfg80211: validate PMSR FTM preamble range Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 081/675] wifi: cfg80211: reject unsupported PMSR FTM location requests Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 082/675] wifi: mac80211: avoid non-S1G AID fallback for S1G assoc Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 083/675] wifi: mac80211: free AP_VLAN bc_buf SKBs outside IRQ lock Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 084/675] wifi: brcmfmac: initialize SDIO data work before cleanup Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 085/675] wifi: cfg80211: bound element ID read when checking non-inheritance Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 086/675] firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit() Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 087/675] firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 088/675] ASoC: meson: aiu: fifo-spdif: soft reset the S/PDIF datapath on start/stop Greg Kroah-Hartman
2026-07-30 14:06 ` [PATCH 6.18 089/675] ASoC: amd: ps: disable MSI on resume in ACP PCI driver Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 090/675] ASoC: amd: ps: fix wrong ACP version string in pci_request_regions() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 091/675] ASoC: amd: ps: replace bitwise OR with logical OR in IRQ return check Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 092/675] ASoC: cs42l43: Correct report for forced microphone jack Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 093/675] ASoC: tas2562: fix deprecated shut-down GPIO always cleared after lookup Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 094/675] firmware: arm_scmi: Rate-limit queue-full warnings in IRQ context Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 095/675] cpufreq: Make cpufreq_update_pressure() fall back to cpuinfo.max_freq Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 096/675] ppp: defer channel free to an RCU grace period to fix pppol2tp RX UAF Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 097/675] ipv4: fib: free fib_alias with kfree_rcu() on insert error path Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 098/675] net/iucv: take a reference on the socket found in afiucv_hs_rcv() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 099/675] udmabuf: Ensure to perform cache synchronisation in begin_cpu_udmabuf() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 100/675] scsi: core: wake eh reliably when using scsi_schedule_eh Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 101/675] ata: sata_dwc_460ex: enable SATA interrupts only after IRQ handler is registered Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 102/675] ata: sata_dwc_460ex: use platform_get_irq() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 103/675] ata: sata_dwc_460ex: fix clear_interrupt_bit() clearing all pending interrupts Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 104/675] ata: sata_dwc_460ex: fix infinite loop in NCQ tag completion bit-scanning Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 105/675] accel/ivpu: Fix wrong register read in LNL failure diagnostics Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 106/675] ALSA: usb-audio: Skip DSD quirk for Musical Fidelity M6s DAC Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 107/675] Bluetooth: qca: fix NVM tag length underflow in TLV parser Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 108/675] Bluetooth: MGMT: revalidate LOAD_CONN_PARAM queued update Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 109/675] Bluetooth: hci_sync: extend conn_hash lookup critical sections Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 110/675] Bluetooth: mgmt: fix locking in unpair_device/disconnect_sync Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 111/675] Bluetooth: mgmt: hold reference for hci_conn in mgmt_pending_cmds Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 112/675] Bluetooth: hci_qca: Clear memdump state on invalid dump size Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 113/675] smb/client: handle overlapping allocated ranges in fallocate Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 114/675] drm/i915/gt: use correct selftest config symbol Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 115/675] can: raw: add locking for raw flags bitfield Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 116/675] powerpc/85xx: Add fsl,ifc to common device ids Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 117/675] powerpc/time: Prepare to stop elapsing in dynticks-idle Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 118/675] powerpc/vtime: Initialize starttime at boot for native accounting Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 119/675] bpf, sockmap: Reject unhashed UDP sockets on sockmap update Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 120/675] drm/panthor: Check debugfs GEM lock initialization Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 121/675] s390/checksum: Fix csum_partial() without vector facility Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 122/675] riscv: hwprobe: Avoid uninitialized read in hwprobe_get_cpus() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 123/675] can: j1939: fix lockless local-destination check Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 124/675] drm/xe: Allow the caller to pass guc_buf_cache size Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 125/675] drm/xe/sa: Shadow buffer support in the sub-allocator pool Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 126/675] drm/xe/vf: Shadow buffer management for CCS read/write operations Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 127/675] drm/xe/vf: Fix VF CCS attach/detach race with in-flight BO moves Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 128/675] drm/xe/wopcm: fix WOPCM size for LNL+ Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 129/675] ksmbd: pin conn during async oplock break notification Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 130/675] ksmbd: validate compound request size before reading StructureSize2 Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 131/675] drm/i915/wm: clear the plane ddb_y entries on plane disable Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 132/675] drm/i915/selftests: Fix GT PM sort comparators Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 133/675] accel/amdxdna: Fix use-after-free of mm_struct in job scheduler Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 134/675] tcp: fix TIME_WAIT socket reference leak on PSP policy failure Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 135/675] dpll: fix NULL pointer dereference in dpll_msg_add_pin_ref_sync() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 136/675] net/sched: act_tunnel_key: Defer dst_release to RCU callback Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 137/675] sctp: fix auth_hmacs array size in struct sctp_cookie Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 138/675] mpls: fix NULL deref in mpls_valid_fib_dump_req() on CONFIG_INET=n Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 139/675] usb: core: sysfs: add lock to bos_descriptors_read() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 140/675] wifi: at76c50x-usb: avoid length underflow in at76_guess_freq() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 141/675] usb: core: port: Deattach Type-C connector on component unbind Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 142/675] usb: musb: omap2430: Do not put borrowed of_node in probe Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 143/675] USB: storage: add NO_ATA_1X quirk for Longmai USB Key Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 144/675] usb: chipidea: fix usage_count leak when autosuspend_delay is negative Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 145/675] usb: gadget: dummy_hcd: prevent fifo_req reuse during giveback Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 146/675] usb: gadget: f_midi: cancel pending IN work before freeing the midi object Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 147/675] usb: gadget: printer: fix infinite loop in printer_read() Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 148/675] USB: gadget: snps-udc: fix device name leak on probe failure Greg Kroah-Hartman
2026-07-30 14:07 ` [PATCH 6.18 149/675] USB: gadget: fsl-udc: " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 150/675] USB: gadget: fsl-udc: fix dev_printk() device Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 151/675] usb: gadget: f_ncm: validate datagram bounds in ncm_unwrap_ntb() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 152/675] usb: gadget: udc: bdc: free IRQ and drain func_wake_notify before teardown Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 153/675] usb: gadget: uvc: clamp SEND_RESPONSE length to the response buffer Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 154/675] USB: serial: ftdi_sio: add support for E+H FXA291 Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 155/675] USB: serial: io_edgeport: cap received transmit credits Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 156/675] USB: serial: keyspan_pda: fix data loss on receive throttling Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 157/675] USB: serial: option: add TDTECH MT5710-CN Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 158/675] usb: typec: ucsi: Detect and skip duplicate altmodes from buggy firmware Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 159/675] usb: typec: ucsi: Add duplicate detection to nvidia registration path Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 160/675] wifi: mwifiex: fix freeze for 60 seconds caused by request_firmware Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 161/675] RISC-V: KVM: Serialize virtual interrupt pending state updates Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 162/675] Revert "drm/amd/display: Add missing kdoc for ALLM parameters" Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 163/675] usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 164/675] selftests/bpf: Adjust verifier_map_ptr for the maps excl field Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 165/675] selftests/bpf: Keep verifier_map_ptr exercising ops pointer access Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 166/675] wifi: ath9k: hif_usb: dont dereference hif_dev after re-arming firmware request Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 167/675] wifi: ath11k: fix NULL pointer dereference in ath11k_hal_srng_access_begin Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 168/675] hwmon: (corsair-psu) Stop device IO before calling hid_hw_stop Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 169/675] hwmon: (corsair-cpro) " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 170/675] hwmon: (gigabyte_waterforce) " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 171/675] hwmon: (nzxt-smart2) " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 172/675] hwmon: (nzxt-kraken3) " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 173/675] watchdog: pretimeout: Fix UAF in watchdog_unregister_governor() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 174/675] watchdog: airoha: Prevent division by zero when clock frequency is zero Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 175/675] wifi: ath11k: fix potential buffer underflow in ath11k_hal_rx_msdu_list_get() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 176/675] wifi: ath11k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 177/675] wifi: ath12k: " Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 178/675] firewire: net: Fix fragmented datagram reassembly Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 179/675] wifi: ath6kl: fix OOB read from firmware num_msg in TX complete handler Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 180/675] wifi: ath6kl: fix OOB read from firmware IE lengths in connect event Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 181/675] wifi: carl9170: bound memcpy length in cmd callback to prevent OOB read Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 182/675] wifi: carl9170: fix OOB read from off-by-two in TX status handler Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 183/675] wifi: carl9170: fix buffer overflow in rx_stream failover path Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 184/675] btrfs: declare btrfs_ioctl_search_args_v2::buf as __u8 Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 185/675] btrfs: fix u32 to s64 type conversion in dirty_metadata_bytes accounting Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 186/675] btrfs: dont propagate EXTENT_FLAG_LOGGING to split extent maps Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 187/675] btrfs: free mapping node on duplicate reloc root insert Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 188/675] ASoC: tas2781: bound firmware description string parsing Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 189/675] ASoC: sun4i-codec: Set quirks.playback_only for H616 codec Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 190/675] ALSA: hda: cs35l41: validate and free ACPI mute object Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 191/675] ASoC: bt-sco: fix duplicate DAPM widget names for wideband DAI Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 192/675] ASoC: cs35l56: Dont use devres to unregister component Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 193/675] ASoC: cs35l56: Fix potential probe() deadlock Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 194/675] ASoC: cs35l56: Use complete_all() to signal init_completion Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 195/675] wifi: iwlwifi: mvm: validate SAR GEO response payload size Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 196/675] wifi: iwlwifi: fix pointer arithmetic in iwl_add_mcc_to_tas_block_list Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 197/675] wifi: iwlwifi: validate payload length in iwl_pnvm_complete_fn Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 198/675] wifi: iwlwifi: mvm: fix read in wake packet notification handler Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 199/675] usb: atm: ueagle-atm: reject descriptors that confuse probe and disconnect Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 200/675] drivers/virt: pkvm: Fix end calculation in mmio_guard_ioremap_hook() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 201/675] hwmon: (asus-ec-sensors) fix looping over banks while reading from EC Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 202/675] hwmon: (asus-ec-sensors) fix EC read intervals Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 203/675] hwmon: (asus-ec-sensors) add missed handle for ENOMEM Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 204/675] smb: client: validate DFS referral PathConsumed Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 205/675] ovpn: avoid putting unrelated P2P peer on socket release Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 206/675] selftests/net: ovpn: fix getaddrinfo memory leak in ovpn_parse_remote() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 207/675] ovpn: fix use after free in unlock_ovpn() Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 208/675] ovpn: use monotonic clock for peer keepalive timeouts Greg Kroah-Hartman
2026-07-30 14:08 ` [PATCH 6.18 209/675] hwmon: occ: validate poll response sensor blocks Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 210/675] regulator: mt6358: use regmap helper to read fixed LDO calibration Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 211/675] Bluetooth: btusb: validate Realtek vendor event length Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 212/675] net: phy: marvell: fix return code Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 213/675] netlink: specs: rt-link: convert bridge port flag attributes to u8 Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 214/675] net/packet: avoid fanout hook re-registration after unregister Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 215/675] bonding: fix devconf_all NULL dereference when IPv6 is disabled Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 216/675] rds: drop incoming messages that cross network namespace boundaries Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 217/675] gtp: parse extension headers before reading inner protocol Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 218/675] rxrpc: fix io_thread race in rxrpc_wake_up_io_thread() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 219/675] dpaa2-switch: put MAC endpoint device on disconnect Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 220/675] net: airoha: Fix potential use-after-free in airoha_ppe_deinit() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 221/675] dpaa2-eth: put MAC endpoint device on disconnect Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 222/675] net: airoha: Fix DMA direction for NPU mailbox buffer Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 223/675] iommu/amd: Wait for completion instead of returning early in iommu_completion_wait() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 224/675] wifi: mac80211: tear down new links on vif update error path Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 225/675] nfp: Check resource mutex allocation Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 226/675] wan: wanxl: Only reset hardware after BAR mapping Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 227/675] vhost-net: fix TX stall when vhost owns virtio-net header Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 228/675] wifi: mwifiex: bound uAP association event IEs to the event buffer Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 229/675] iommu/amd: Bound the early ACPI HID map Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 230/675] iommu/intel: Fix out-of-bounds memset in dmar_latency_disable() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 231/675] wifi: mac80211: recalculate TIM when a station enters power save Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 232/675] pds_core: reject component parameter in legacy firmware update Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 233/675] arm64: Correct value returned by ESR_ELx_FSC_ADDRSZ_nL() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 234/675] amd-xgbe: fix MAC_AUTO_SW handling in CL37 AN Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 235/675] soreuseport: Clear sk_reuseport_cb before failure in sk_clone() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 236/675] net: Call net_enable_timestamp() " Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 237/675] net: txgbe: fix FDIR filter leak on remove Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 238/675] sctp: fix auth_chunk_list capacity check in sctp_auth_ep_add_chunkid Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 239/675] pds_core: fix deadlock between reset thread and remove Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 240/675] pds_core: fix use-after-free on workqueue during remove Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 241/675] pds_core: yield the CPU while waiting for the adminq to drain Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 242/675] pds_core: order completion reads after the ownership check Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 243/675] pds_core: fix auxiliary device add/del races Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 244/675] pds_core: check for workqueue allocation failure Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 245/675] sctp: validate stream count in sctp_process_strreset_inreq() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 246/675] net: mctp i3c: clean up notifier and buses if driver register fails Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 247/675] tls: device: push pending open record on splice EOF Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 248/675] selftests: af_unix: add USER_NS config Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 249/675] selftests: openvswitch: add config file Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 250/675] selftests: ovpn: add IPV6 and VETH configs Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 251/675] selftests: ovpn: increase timeout Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 252/675] selftests: drv-net: " Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 253/675] gtp: check skb_pull_data() return in gtp1u_send_echo_resp() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 254/675] nexthop: initialize extack in nh_res_bucket_migrate() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 255/675] tipc: fix infinite loop in __tipc_nl_compat_dumpit Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 256/675] ppp: enable TX scatter-gather Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 257/675] ppp: dont store tx skb in the fastpath Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 258/675] ppp: annotate concurrent dev->stats accesses Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 259/675] wifi: mt76: mt7925: guard link STA in decap offload Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 260/675] wifi: mt76: mt7915: guard HE capability lookups Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 261/675] wifi: mt76: connac: fix possible NULL-pointer deref in mt76_connac_mcu_uni_bss_he_tlv() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 262/675] wifi: mt76: mt7925: fix possible NULL-pointer deref in mt7925_mcu_bss_he_tlv() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 263/675] wifi: mt76: mt7996: check pointer returned by mt76_connac_get_he_phy_cap() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 264/675] wifi: mt76: mt7925: fix crash in reset link replay Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 265/675] wifi: mt76: mt7996: fix possible NULL-pointer deref in mt7996_mcu_sta_bfer_eht() Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 266/675] wifi: brcmfmac: fix 802.1X-SHA256 call trace warning Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 267/675] ovl: fix trusted xattr escape prefix matching Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 268/675] drm/panel: s6e3ha8: fix unmet dependency on DRM_DISPLAY_HELPER Greg Kroah-Hartman
2026-07-30 14:09 ` [PATCH 6.18 269/675] cred: add scoped_with_kernel_creds() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 270/675] ovl: add override_creds cleanup guard extension for overlayfs Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 271/675] ovl: port ovl_copyfile() to cred guard Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 272/675] ovl: check access to copy_file_range source with src mounter creds Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 273/675] amt: re-read skb header pointers after every pull Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 274/675] amt: make the head writable before rewriting the L2 header Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 275/675] net: bridge: vlan: fix vlan range dumps starting with pvid Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 276/675] net: hsr: fix memory leak on slave unregistration by removing synced VLANs Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 277/675] net: dpaa: fix mode setting Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 278/675] sctp: auth: verify auth requirement when auth_chunk is NULL Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 279/675] vmxnet3: fix BUG_ON in vmxnet3_get_hdr_len() for Geneve packets Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 280/675] drm/xe/i2c: Allow per domain unique id Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 281/675] drm/xe/vm: Fix SVM leak on resv obj alloc failure in xe_vm_create() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 282/675] iomap: correct the range of a partial dirty clear Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 283/675] tipc: fix u16 MTU truncation in media and bearer MTU validation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 284/675] drm/tests: shmem: Set DMA mask to 64-bit in drm_gem_shmem Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 285/675] bpf: tcp: fix double sock release on batch realloc Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 286/675] net: stmmac: remove xstats.pcs_* members Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 287/675] net: stmmac: socfpga: Agilex5 EMAC platform configuration Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 288/675] net: stmmac: socfpga: Enable TBS support for Agilex5 Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 289/675] net: stmmac: socfpga: Add hardware supported cross-timestamp Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 290/675] net: stmmac: cores: remove many xxx_SHIFT definitions Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 291/675] net: stmmac: xgmac: fix l4 filter port overwrite on register update Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 292/675] net: stmmac: fix l3l4 filter rejecting unsupported offload requests Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 293/675] net: stmmac: reset residual action in L3L4 filters on delete Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 294/675] net: stmmac: enable the MAC on link up for all supported speeds Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 295/675] net: gre: fix lltx regression for GRE tunnels with SEQ/CSUM Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 296/675] octeontx2-vf: set TC flower flag on MCAM entry allocation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 297/675] ipv4: icmp: fill flow parameters in icmp_route_lookup decoy lookup Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 298/675] ppp: annotate data races in ppp_generic Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 299/675] hinic: remove unused ethtool RSS user configuration buffers Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 300/675] net: qrtr: restrict socket creation to the initial network namespace Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 301/675] raw: annotate lockless match fields in raw_v4_match() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 302/675] net/mlx5: Refactor EEPROM query error handling to return status separately Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 303/675] net/mlx5: Fix MCIA register buffer overflow on 32 dword reads Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 304/675] net/mlx5: E-Switch, fix zero num_dest in prio_tag egress vlan rule Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 305/675] net/mlx5e: Report zero bandwidth for non-ETS traffic classes Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 306/675] net/mlx5e: Reject unsupported CB Shaper TSA in ETS validation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 307/675] octeontx2-pf: tc: fix egress ratelimiting Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 308/675] net: ipv6: fix dif and sdif mismatch in raw6_icmp_error Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 309/675] ice: allow creating VFs when !CONFIG_ICE_SWITCHDEV Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 310/675] ice: fix LAG recipe to profile association Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 311/675] ice: prevent tstamp ring allocation for non-PF VSI types Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 312/675] ipv6: Change allocation flags to match rcu_read_lock section requirements Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 313/675] rds: tcp: unregister sysctl before tearing down listen socket Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 314/675] ptp: netc: explicitly clear TMR_OFF during initialization Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 315/675] mctp: check register_netdevice_notifier() error in mctp_device_init() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 316/675] net: airoha: fix ETS channel derivation in airoha_tc_setup_qdisc_ets() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 317/675] bpf, sockmap: Fix cork use-after-free in tcp_bpf_sendmsg() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 318/675] drm: renesas: rzg2l_mipi_dsi: Increase reset deassertion delay Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 319/675] drm: renesas: rzg2l_mipi_dsi: Move rzg2l_mipi_dsi_set_display_timing() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 320/675] drm/tidss: Fix missing drm_bridge_add() call Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 321/675] drm/rockchip: cdn-dp: add missing check in cdn_dp_config_video() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 322/675] drm/rockchip: analogix_dp: Add missing error check for platform_get_resource() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 323/675] drm/imagination: Count paired job fence as dependency in prepare_job() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 324/675] drm/bridge: cdns-dsi: Replace deprecated UNIVERSAL_DEV_PM_OPS() Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 325/675] drm/dp/mst: fix OOB reads in remote DPCD/I2C sideband reply parsers Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 326/675] drm/dp/mst: fix buffer overflows in sideband chunk accumulation Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 327/675] drm/imagination: Fit paired fragment job in the correct CCCB Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 328/675] drm/dp/mst: fix OOB reads on 2-byte fields in sideband reply parsers Greg Kroah-Hartman
2026-07-30 14:10 ` [PATCH 6.18 329/675] drm/amdgpu/gfx: fix cleaner shader IB buffer overflow Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 330/675] drm/amdgpu/uvd: Fix forcing MSG, FB BOs into VCPU segment when it isnt at 0 (v2) Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 331/675] drm/amdgpu/uvd: Place VCPU BO only in VRAM for UVD 4.x and older Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 332/675] drm/amdgpu: check amdgpu_vm_bo_find() result in GET_MAPPING_INFO Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 333/675] drm/sysfb: Do not page-align visible size of the framebuffer Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 334/675] drm/sysfb: Avoid truncating maximum stride Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 335/675] drm/amdgpu/gfx9: Fix Ring and IB test fail after mode2 Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 336/675] drm/amdgpu: Fix amdgpu_bo_move() when old_mem and new_mem are both GTT Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 337/675] drm/amdgpu: validate CP_GFX_SHADOW chunk size in CS pass1 Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 338/675] drm/nouveau: fix reversed error cleanup order in ucopy functions Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 339/675] drm/sysfb: Avoid possible truncation with calculating visible size Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 340/675] drm/sysfb: Return errno code from drm_sysfb_get_visible_size() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 341/675] drm/displayid: fix Tiled Display Topology ID size Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 342/675] drm/i915/gem: Add missing nospec on parallel submit slot Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 343/675] drm/nouveau/acr: fix missing nvkm_done() in error path of nvkm_acr_oneinit() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 344/675] drm/radeon: fix r100_copy_blit for large BOs Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 345/675] drm/xe: Return error on non-migratable faults requiring devmem Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 346/675] drm/xe: Fix PTE index in xe_vm_populate_pgtable() for chunked binds Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 347/675] drm/xe: Hold a dma-buf reference for imported BOs Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 348/675] drm/imagination: Fix double call to drm_sched_entity_fini() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 349/675] drm/imagination: Fix user array stride in pvr_set_uobj_array() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 350/675] drm/imagination: fix error checking of pvr_vm_context_lookup() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 351/675] drm/imagination: acquire vm_ctx->lock before mapping memory to GPU VM Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 352/675] drm/amdkfd: Use kvcalloc to allocate arrays Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 353/675] drm/amdkfd: Check bounds in allocate_event_notification_slot Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 354/675] drm/amdkfd: Check bounds on CRIU restore queue type and mqd size Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 355/675] drm/amdkfd: fix 32-bit overflow in CWSR total size calculation Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 356/675] drm/amd/display: Handle struct drm_plane_state.ignore_damage_clips Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 357/675] 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.18 358/675] drm/virtio: bound EDID block reads to the response buffer Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 359/675] drm/i915/hdcp: require monotonically increasing seq_num_v Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 360/675] drm/i915/hdcp: check streams[] bounds before overflow Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 361/675] drm/amdgpu/sdma7.0: replace BUG_ON() with WARN_ON() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 362/675] drm/amdgpu/sdma6.0: " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 363/675] drm/amdgpu/sdma5.2: " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 364/675] drm/amdgpu/sdma5.0: " Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 365/675] drm/i915: Return NULL on error in active_instance Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 366/675] drm/i915/bios: range check LFP Data Block panel_type2 Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 367/675] drm/amd/amdgpu: disable ASPM on VI if pcie dpm is disabled Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 368/675] drm/amdgpu: fix lifetime issue of amdgpu_vm_get_task_info_pasid() Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 369/675] drm/i915/gem: Do not leak siblings[] on proto context error Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 370/675] drm/i915/gem: Fix NULL deref in I915_CONTEXT_PARAM_SSEU Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 371/675] drm/i915/mst: limit DP MST ESI service loop Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 372/675] drm/amd/pm: fix smu14 power limit range calculation Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 373/675] drm/gfx10: Program DB_RING_CONTROL Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 374/675] drm/virtio: Dont detach GEM from a non-created context Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 375/675] drm/ttm: Account for NULL and handle pages in ttm_pool_backup Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 376/675] drm/panthor: return error on truncated firmware Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 377/675] drm/amdgpu: Release VFCT ACPI table reference Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 378/675] drm/amdgpu: Fix VFCT bus number matching with soft filter Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 379/675] drm/amd/pm/ci: Dont disable MCLK DPM on Bonaire 0x6658 (R7 260X) Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 380/675] drm/amd/display: set new_stream to NULL after release Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 381/675] drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 382/675] drm/amd/display: dce100: skip non-DP stream encoders for DP MST Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 383/675] drm/amd/display: Force PWM backlight on Lenovo Legion 5 15ARH05 Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 384/675] drm/amd/display: Fix backlight max_brightness to match exported range Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 385/675] drm/amdgpu: Disable PCIe dynamic speed switching on Ryzen Pinnacle Ridge Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 386/675] drm/amdgpu: fix bo->pin leaking in amdgpu_bo_create_reserved Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 387/675] drm/amd/display: Fix flip-done timeouts on mode1 reset Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 388/675] drm/vc4: Shut down BO cache timer before teardown Greg Kroah-Hartman
2026-07-30 14:11 ` [PATCH 6.18 389/675] drm/amd/display: Fix missing DCE check in dm_gpureset_toggle_interrupts() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 390/675] drm/vmwgfx: Validate vmw_surface_metadata::array_size Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 391/675] drm/vc4: Prevent shader BO mappings from becoming writable Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 392/675] drm/gpusvm: Fix MM reference leak in drm_gpusvm_range_evict Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 393/675] drm/v3d: Reach the GMP through the hub registers on V3D 7.x Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 394/675] media: airspy: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 395/675] media: amlogic-c3: Add validations for ae and awb config Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 396/675] media: aspeed: fix missing of_reserved_mem_device_release() on probe failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 397/675] media: cec: seco: unregister adapter on IR " Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 398/675] media: cedrus: clean up media device on " Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 399/675] media: cedrus: Fix missing cleanup in error path Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 400/675] media: cedrus: skip invalid H.264 reference list entries Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 401/675] media: chips-media: wave5: Move src_buf Removal to finish_encode Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 402/675] media: cx231xx: fix devres lifetime Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 403/675] media: cx23885: add ioremap return check and cleanup Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 404/675] media: i2c: alvium: fix critical pointer access in alvium_ctrl_init Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 405/675] media: imx219: Fix maximum frame length in lines Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 406/675] media: intel/ipu6: Improve DWC PHY HSFREQRANGE band selection for overlapping ranges Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 407/675] media: iris: Fix use IRQF_NO_AUTOEN when requesting the IRQ Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 408/675] media: marvell-cam: fix missing pci_disable_device() on remove Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 409/675] media: meson: vdec: Fix memory leak in error path of vdec_open Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 410/675] media: msi2500: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 411/675] media: nuvoton: npcm-video: fix error handling in npcm_video_init() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 412/675] media: nuvoton: npcm-video: fix memory leaks in probe and remove Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 413/675] media: nxp: imx8-isi: Add missing v4l2_subdev_cleanup() in crossbar and pipe Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 414/675] media: nxp: imx8-isi: Clean up already-initialized pipes on probe failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 415/675] media: nxp: imx8-isi: Fix missing v4l2_subdev_cleanup() in pipe init error path Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 416/675] media: nxp: imx8-isi: Fix potential out-of-bounds issues Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 417/675] media: nxp: imx8-isi: Fix scale factor calculation for hardware rounding Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 418/675] media: pci: dm1105: Free allocated workqueue Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 419/675] media: pwc: Drain fill_buf on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 420/675] media: pwc: Return queued buffers " Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 421/675] media: qcom: camss: Fix RDI streaming for CSID 680 Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 422/675] media: qcom: camss: Fix RDI streaming for CSID GEN2 Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 423/675] media: qcom: camss: Fix RDI streaming for CSID GEN3 Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 424/675] media: radio-si476x: Unregister v4l2_device on probe failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 425/675] media: rtl2832: fix use-after-free in rtl2832_remove() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 426/675] media: rtl2832_sdr: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 427/675] media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 428/675] media: saa7134: Fix a possible memory leak in saa7134_video_init1 Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 429/675] media: stm32-dcmipp: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 430/675] media: stm32: dcmi: unregister notifier on probe failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 431/675] media: sun4i-csi: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 432/675] media: synopsys: hdmirx: Fix HPD lane hold time Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 433/675] media: tegra-video: vi: fix invalid u32 return value in format lookup Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 434/675] media: ti: vpe: unwind v4l2 device registration on probe error Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 435/675] media: v4l2-ctrls-request: add NULL check in v4l2_ctrl_request_complete() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 436/675] media: v4l2-ctrls: validate HEVC active reference counts Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 437/675] media: v4l2-fwnode: Fix subdev owner overwritten in v4l2_async_register_subdev_sensor() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 438/675] media: v4l2-subdev: Fail {enable,disable}_streams and s_streaming nicely Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 439/675] media: vb2: use ssize_t for vb2_read/vb2_write Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 440/675] media: verisilicon: Export only needed pixels formats Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 441/675] media: vidtv: fix reference leak on failed device registration Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 442/675] media: vimc: " Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 443/675] media: vivid: add vivid_update_reduced_fps() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 444/675] media: vivid: check for vb2_is_busy() when toggling caps Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 445/675] media: vivid: fix cleanup bugs in vivid_init() Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 446/675] media: vpif_capture: fix OF node reference imbalance Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 447/675] ALSA: hda/realtek: Fix speakers on Lunnen Ground 14 Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 448/675] ALSA: seq: close a re-opened queue timer in the destructor Greg Kroah-Hartman
2026-07-30 14:12 ` [PATCH 6.18 449/675] ALSA: hda: codecs: hdmi: disable keep-alive before audio format change Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 450/675] ALSA: timer: drain a slaves callback before its master detaches it Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 451/675] ALSA: timer: dont re-enter an instance callback that is still running Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 452/675] wifi: ath6kl: fix OOB access from firmware ADDBA window size Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 453/675] wifi: ath6kl: fix use-after-free in aggr_reset_state() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 454/675] wifi: mwifiex: fix NULL dereference when the AP has HT-cap but no HT-oper Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 455/675] wifi: wilc1000: validate assoc response length before subtracting header Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 456/675] wifi: mt76: mt7615: drop TXRX_NOTIFY on non-mmio buses Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 457/675] wifi: mt76: mt7921: " Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 458/675] wifi: mt76: mt7925: " Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 459/675] wifi: brcmfmac: make release_scratchbuffers idempotent Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 460/675] wifi: brcmfmac: set F2 blocksize to 256 for BCM43752 Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 461/675] wifi: ath11k: fix refcount leak in ath11k_ahb_fw_resources_init() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 462/675] staging: rtl8723bs: fix OOB reads in rtw_get_wps_ie() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 463/675] staging: rtl8723bs: fix inverted HT40 secondary channel offset Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 464/675] Bluetooth: hci_sync: Protect UUID list traversal Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 465/675] Bluetooth: RFCOMM: Fix session UAF in set_termios Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 466/675] exec: fix unsigned loop counter wrap in transfer_args_to_stack() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 467/675] binfmt_misc: set have_execfd only once the interpreter is opened Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 468/675] platform/loongarch: laptop: Explicitly reset bl_powered state when suspend Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 469/675] rust_binder: only print failure if error has source Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 470/675] rust: time: fix as_micros_ceil() to round correctly for negative Delta Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 471/675] rust: allow `clippy::unwrap_or_default` globally Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 472/675] objtool/rust: add one more `noreturn` Rust function for Rust 1.99.0 Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 473/675] LoongArch: Fix address space mismatch in kexec command line lookup Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 474/675] LoongArch: Fix oops during single-step debugging Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 475/675] LoongArch: Move jump_label_init() before parse_early_param() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 476/675] LoongArch: Retrieve CPU package ID from PPTT when available Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 477/675] cdrom: fix stack out-of-bounds read in CDROMVOLCTRL Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 478/675] rhashtable: clear stale iter->p on table restart Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 479/675] firmware: stratix10-svc: fix memory leaks and list corruption bugs Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 480/675] x86/boot/compressed: Disable jump tables Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 481/675] comedi: comedi_parport: deal with premature interrupt Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 482/675] uio_hv_generic: Bind to FCopy device by default Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 483/675] serial: sc16is7xx: implement gpio get_direction() callback Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 484/675] serial: 8250_mid: Fix NULL function pointer dereference on DNV/ICX-D/SNR platforms Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 485/675] selftests: ntsync: correct CONFIG_NTSYNC name Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 486/675] mei: bus: access mei_device under device_lock on cleanup Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 487/675] intel_th: fix MSC output device reference leak Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 488/675] misc: nsm: only unlock nsm_dev on post-lock error paths Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 489/675] misc: nsm: pin the module while the device is open Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 490/675] tracing: Fix context switch counter truncation Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 491/675] tracing: Fix mmiotrace possible NULL dereferencing of hiter->dev Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 492/675] tracing: Fix resource leak on mmiotrace trace_pipe close Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 493/675] tracing: Fix union collision of module and refcnt for dynamic events Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 494/675] tracing/eprobe: Fix exact system name matching in eprobe_dyn_event_match() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 495/675] tracing/probes: Avoid temporary buffer truncation in trace_probe_match_command_args() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 496/675] tracing/probes: Fix potential underflow in LEN_OR_ZERO macro Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 497/675] tracing/probes: Prevent out-of-bounds write in __trace_probe_log_err() Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 498/675] arm64: make huge_ptep_get handled unaligned addresses Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 499/675] arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 500/675] Revert "arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates" Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 501/675] mptcp: decrement subflows counter on failed passive join Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 502/675] mptcp: only set DATA_FIN when a mapping is present Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 503/675] mptcp: pm: userspace: fix use-after-free in get_local_id Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 504/675] afs: Fix afs_edit_dir_remove() to get, not find, block 0 Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 505/675] mm/kmemleak: fix checksum computation for per-cpu objects Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 506/675] mm/huge_memory: set PG_has_hwpoisoned only after new folio head is established Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 507/675] sctp: dont free the ASCONFs own transport in DEL-IP processing Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 508/675] sctp: avoid auth_enable sysctl UAF during netns teardown Greg Kroah-Hartman
2026-07-30 14:13 ` [PATCH 6.18 509/675] sctp: close UDP tunnel sockets " Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 510/675] ceph: add owner/capability checks for CEPH_IOC_SET_LAYOUT* Greg Kroah-Hartman
2026-07-30 17:40 ` Ilya Dryomov
2026-07-30 14:14 ` [PATCH 6.18 511/675] ceph: fix pre-auth out-of-bounds read on snaptrace in ceph_handle_caps() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 512/675] ceph: fix refcount leak in ceph_readdir() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 513/675] ceph: fix writeback_count leak in write_folio_nounlock() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 514/675] libceph: bound get_version reply decode to front len Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 515/675] libceph: Fix multiplication overflow in decode_new_up_state_weight() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 516/675] libceph: guard missing CRUSH type name lookup Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 517/675] libceph: refresh auth->authorizer_buf{,_len} after authorizer update Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 518/675] libceph: Reject monmaps advertising zero monitors Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 519/675] libceph: reject zero bucket types in crush_decode Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 520/675] libceph: remove debugfs files before client teardown Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 521/675] amt: fix use-after-free in AMT delayed works Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 522/675] ASoC: fsl: imx-card: Skip sysclk reset for active DAIs in shutdown Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 523/675] ASoC: fsl_sai: Fix spurious BCLK on resume by clearing BYP Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 524/675] binfmt_elf_fdpic: only honour the first PT_INTERP Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 525/675] fs/super: fix emergency thaw double-unlock of s_umount Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 526/675] fs: preserve ACL_DONT_CACHE state in forget_cached_acl() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 527/675] fscrypt: Add missing superblock check in find_or_insert_direct_key() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 528/675] ftrace: Add global mutex to serialize trace_parser access Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 529/675] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 530/675] iomap: fix out-of-bounds bitmap_set() with zero-length range Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 531/675] iommu/vt-d: Disallow SVA if page walk is not coherent Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 532/675] net: stmmac: intel: skip SerDes reconfig when rate is unchanged Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 533/675] phonet: pep: fix use-after-free in pep_get_sb() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 534/675] vxlan: require CAP_NET_ADMIN in the device netns for changelink Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 535/675] net: slip: serialize receive against buffer reallocation Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 536/675] geneve: require CAP_NET_ADMIN in the device netns for changelink Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 537/675] net/af_iucv: fix NULL deref in afiucv_hs_callback_syn() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 538/675] net/iucv: fix use-after-free of a severed iucv_path Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 539/675] net/mlx5e: Use sender devcom for MPV master-up Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 540/675] net/x25: fix use-after-free in x25_kill_by_neigh() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 541/675] net: gro: fix double aggregation of flush-marked skbs Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 542/675] net: hip04: fix RX buffer leak on build_skb failure Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 543/675] net: pcs: xpcs: fix SGMII state reading Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 544/675] proc: Fix broken error paths for namespace links Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 545/675] ptp: ptp_s390: Add missing facility check Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 546/675] ice: fix PTP Call Trace during PTP release Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 547/675] selftests/ftrace: Reset triggers at top level before instance loop Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 548/675] super: fix emergency thaw deadlock on frozen block devices Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 549/675] rbd: Reset positive result codes to zero in object map update path Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 550/675] smb: client: handle STATUS_STOPPED_ON_SYMLINK responses without a symlink target Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 551/675] ksmbd: defer destroy_previous_session() until after NTLM authentication Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 552/675] gve: fix Rx queue stall on alloc failure Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 553/675] ice: reject out-of-range ptype in ice_parser_profile_init Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 554/675] ice: use READ_ONCE() to access cached PHC time Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 555/675] ila: reload IPv6 header after pskb_may_pull in checksum adjust Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 556/675] mac802154: hold an interface reference across the scan worker Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 557/675] mac802154: llsec: reject frames shorter than the authentication tag Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 558/675] mctp: serial: handle zero-length frames to prevent rx buffer overflow Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 559/675] openvswitch: fix GSO userspace truncation underflow Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 560/675] ovpn: fix peer refcount leak in TCP error paths Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 561/675] ovpn: hold peer before scheduling keepalive work Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 562/675] pppoe: reload header pointer after dev_hard_header() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 563/675] rtase: Workaround for TX hang caused by hardware packet parsing Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 564/675] tcp: initialize standalone TCP-AO response padding Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 565/675] tcp: challenge ACK for non-exact RST in SYN-RECEIVED Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 566/675] tipc: clear sock->sk on the failed-insert path in tipc_sk_create() Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 567/675] vsock/virtio: collapse receive queue under memory pressure Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 568/675] vxlan: mdb: Fix source list corruption on a failed replace Greg Kroah-Hartman
2026-07-30 14:14 ` [PATCH 6.18 569/675] watchdog: s32g_wdt: remove incorrect options in watchdog_info struct Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 570/675] drm/amd/pm: fix amdgpu_pm_info power display units Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 571/675] drm/amd/pm: make pp_features read-only when scpm is enabled Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 572/675] drm/amdgpu/gfx10: replace BUG_ON() with WARN_ON() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 573/675] drm/amdgpu/gfx11: " Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 574/675] drm/amdgpu/gfx12: " Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 575/675] drm/amdgpu/gfx8: drop unecessary BUG_ON() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 576/675] drm/amdgpu/gfx9.4.3: replace BUG_ON() with WARN_ON() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 577/675] drm/amdgpu/gfx9: " Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 578/675] drm/amdgpu/jpeg: fix jpeg_v4_0_3_is_idle detection Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 579/675] drm/amdgpu/jpeg: fix jpeg_v5_0_1_is_idle detection Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 580/675] drm/amdgpu/sdma4.4.2: replace BUG_ON() with WARN_ON() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 581/675] drm/amdgpu/soc24: reset dGPU if suspend got aborted Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 582/675] drm/amdgpu/vce: fix integer overflow in image size Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 583/675] drm/amdgpu/vcn4: avoid rereading IB param length Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 584/675] drm/dp_mst: Handle torn-down topology gracefully in drm_dp_mst_topology_queue_probe() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 585/675] drm/amdgpu: fix division by zero with invalid uvd dimensions Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 586/675] drm/amdgpu: fix resource leak on ACP reset timeout Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 587/675] drm/amdgpu: invoke pm_genpd_remove() before freeing genpd Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 588/675] drm/amdgpu: fix aperture mapping leak Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 589/675] drm/amd/pm: fix smu13 power limit range calculation Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 590/675] drm/amdgpu: fix check in amdgpu_hmm_invalidate_gfx Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 591/675] bpf: Fix same-register dst/src OOB read and pointer leak in sock_ops Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 592/675] dm-verity-fec: fix the size of dm_verity_fec_io::erasures Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 593/675] dm-verity-fec: fix reading parity bytes split across blocks (take 3) Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 594/675] dm-verity-fec: replace {MAX,MIN}_RSN with {MIN,MAX}_ROOTS Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 595/675] dm-verity: fix buffer overflow in FEC calculation Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 596/675] drm/xe/uapi: Reject coh_none PAT index for CPU_ADDR_MIRROR Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 597/675] ublk: wait on ublk_dev_ready() instead of ub->completion Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 598/675] net: qrtr: ns: Raise node count limit to 512 Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 599/675] ksmbd: validate num_subauth when copying ACE in set_ntacl_dacl Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 600/675] ksmbd: restore DACL size on check_add_overflow() to avoid malformed ACL Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 601/675] ksmbd: bound DACL dedup walk to copied ACEs Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 602/675] ksmbd: validate ACE size against SID sub-authorities Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 603/675] fscrypt: Avoid dynamic allocation in fscrypt_get_devices() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 604/675] drm/amd/display: Fix DTB DTO updates breaking live pixel rate sources Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 605/675] landlock: Fix formatting Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 606/675] landlock: Account all audit data allocations to user space Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 607/675] audit: widen ino fields to u64 Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 608/675] audit: use unsigned int instead of unsigned Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 609/675] audit: fix recursive locking deadlock in audit_dupe_exe() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 610/675] fuse-uring: fix race between registration and connection abortion Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 611/675] xfs: dont replace the wrong part of the cow fork Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 612/675] vduse: return internal vq group struct as map token Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 613/675] vduse: remove unused vaddr parameter of vduse_domain_free_coherent Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 614/675] vduse: take out allocations from vduse_dev_alloc_coherent Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 615/675] VDUSE: avoid leaking information to userspace Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 616/675] arm64: dts: qcom: correct RBR opp entry Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 617/675] arm64: dts: qcom: hamoa: Fix OPP tables for all DisplayPort controllers Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 618/675] netfilter: nf_tables: remove register tracking infrastructure Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 619/675] netfilter: nft_fib: reject fib expression on the netdev egress hook Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 620/675] netfilter: nf_conntrack_sip: remove net variable shadowing Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 621/675] netfilter: nf_conntrack_sip: validate skb_dst() before accessing it Greg Kroah-Hartman
2026-07-30 14:15 ` Greg Kroah-Hartman [this message]
2026-07-30 14:15 ` [PATCH 6.18 623/675] gpu/buddy: bail out of try_harder when alignment cannot be honoured Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 624/675] pinctrl: renesas: rzg2l: Use -ENOTSUPP instead of -EOPNOTSUPP Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 625/675] NFSD: pass nfsd_file to nfsd_iter_read() Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 626/675] sunrpc: allocate a separate bvec array for socket sends Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 627/675] SUNRPC: Add helpers to convert xdr_buf byte ranges to scatterlists Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 628/675] SUNRPC: Return an error from xdr_buf_to_bvec() on overflow Greg Kroah-Hartman
2026-07-30 14:15 ` [PATCH 6.18 629/675] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 630/675] cxl/pci: Remove unnecessary CXL RCH " Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 631/675] cxl/pci: Remove CXL VH handling in CONFIG_PCIEAER_CXL conditional blocks from core/pci.c Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 632/675] cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 633/675] remoteproc: xlnx: Check remote core state Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 634/675] mm/sparse-vmemmap: fix vmemmap accounting underflow Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 635/675] kho: make sure scratch size is always aligned by CMA_MIN_ALIGNMENT_BYTES Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 636/675] mtd: maps: vmu-flash: fix fault in unaligned fixup Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 637/675] thunderbolt: Keep XDomain reference during the lifetime of a service Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 638/675] thunderbolt: Remove service debugfs entries during unregister Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 639/675] thunderbolt: Remove XDomain from the bus without holding tb->lock Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 640/675] thunderbolt: Prevent XDomain delayed work use-after-free on disconnect Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 641/675] dmaengine: dw-edma: Fix confusing cleanup.h syntax Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 642/675] dmaengine: dw-edma-pcie: Reject devices without driver data Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 643/675] ovl: use linked upper dentry in copy-up tmpfile Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 644/675] accel/amdxdna: reject command submission on devices without a submit op Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 645/675] cred: add kernel_cred() helper Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 646/675] dm: avoid leaking the callers thread keyring via the table device file Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 647/675] mmc: vub300: rename probe error labels Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 648/675] mmc: vub300: fix use-after-free on probe failure Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 649/675] fs/resctrl: Split L3 dependent parts out of __mon_event_count() Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 650/675] x86,fs/resctrl: Rename struct rdt_mon_domain and rdt_hw_mon_domain Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 651/675] x86,fs/resctrl: Rename some L3 specific functions Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 652/675] fs/resctrl: Move allocation/free of closid_num_dirty_rmid[] Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 653/675] fs/resctrl: Move RMID initialization to first mount Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 654/675] fs/resctrl: Fix use-after-free during unmount Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 655/675] net: mana: Validate the packet length reported by the NIC Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 656/675] net: mana: Optimize irq affinity for low vcpu configs Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 657/675] octeontx2-af: validate body pcifunc in rvu_mbox_handler_rep_event_notify Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 658/675] octeontx2-af: cn10k: restrict VF LMTLINE sharing to its own PF Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 659/675] bootconfig: move xbc_snprint_cmdline() to lib/bootconfig.c Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 660/675] bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline() Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 661/675] ata: libata-core: Reject an invalid concurrent positioning ranges count Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 662/675] net: ipa: fix SMEM state handle leaks in SMP2P init Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 663/675] pmdomain: imx93-blk-ctrl: convert to devm_* only Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 664/675] pmdomain: imx93-blk-ctrl: Extract PHY as shared domain for DSI/CSI Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 665/675] i3c: mipi-i3c-hci: Fix Hot-Join NACK Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 666/675] i3c: mipi-i3c-hci: Fix handling of shared IRQs during early initialization Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 667/675] mm/damon/core: validate ranges in damon_set_regions() Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 668/675] mm/damon/core: disallow overlapping input ranges for damon_set_regions() Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 669/675] rust: allow `suspicious_runtime_symbol_definitions` lint for Rust >= 1.98 Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 670/675] rust: device: avoid trailing ; in printing macros Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 671/675] usb: gadget: f_tcm: synchronize delayed set_alt with teardown Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 672/675] net/mlx5e: Fix NULL pointer dereference in ioctl module EEPROM query Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 673/675] net: stmmac: fix dwmac4 transmit performance regression Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 674/675] gpu: Fix uninitialized buddy for built-in drivers Greg Kroah-Hartman
2026-07-30 14:16 ` [PATCH 6.18 675/675] KVM: SVM: Bump asid_generation on CPU online to avoid ASID collision after hotplug Greg Kroah-Hartman
2026-07-30 18:17 ` [PATCH 6.18 000/675] 6.18.42-rc1 review Miguel Ojeda
2026-07-30 18:30 ` Wentao Guan
2026-07-30 18:39 ` Florian Fainelli
2026-07-30 20:06 ` Brett A C Sheffield
2026-07-30 20:14 ` Peter Schneider
2026-07-30 21:20 ` Shuah Khan
2026-07-30 21:50 ` Pavel Machek
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=20260730141458.342461372@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