From d32bf877c0c3ebc345b444cbe009b3f44f9f8073 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Wed, 27 May 2026 15:55:06 -0700 Subject: perf/core: out-of-line and export perf_allow_cpu/tracepoint() These helpers are static inline in and reach into sysctl_perf_event_paranoid and security_perf_event_open(), neither of which is itself exported. The perf_allow_* trio is therefore asymmetric: built-in callers can use any of the three, but modular code can only call perf_allow_kernel(). Move both bodies into kernel/events/core.c next to perf_allow_kernel() and export them with EXPORT_SYMBOL_GPL, following the shape of commit 5e9629d0ae97 ("drivers/perf: arm_spe: Use perf_allow_kernel() for permissions"). Existing in-tree callers live in built-in arch and tracing code, so the change is invisible to them. Provide !CONFIG_PERF_EVENTS stubs that fall back to perfmon_capable(), so the helpers stay callable when perf is compiled out. Signed-off-by: John Hubbard Reviewed-by: Ashutosh Dixit Link: https://patch.msgid.link/20260527225507.2044027-2-ashutosh.dixit@intel.com Signed-off-by: Ashutosh Dixit --- include/linux/perf_event.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 48d851fbd8ea..5842552294c1 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1791,22 +1791,8 @@ static inline int perf_is_paranoid(void) } extern int perf_allow_kernel(void); - -static inline int perf_allow_cpu(void) -{ - if (sysctl_perf_event_paranoid > 0 && !perfmon_capable()) - return -EACCES; - - return security_perf_event_open(PERF_SECURITY_CPU); -} - -static inline int perf_allow_tracepoint(void) -{ - if (sysctl_perf_event_paranoid > -1 && !perfmon_capable()) - return -EPERM; - - return security_perf_event_open(PERF_SECURITY_TRACEPOINT); -} +extern int perf_allow_cpu(void); +extern int perf_allow_tracepoint(void); extern int perf_exclude_event(struct perf_event *event, struct pt_regs *regs); @@ -2023,6 +2009,19 @@ perf_event_pause(struct perf_event *event, bool reset) { return 0; } static inline int perf_exclude_event(struct perf_event *event, struct pt_regs *regs) { return 0; } +static inline int perf_allow_kernel(void) +{ + return perfmon_capable() ? 0 : -EACCES; +} +static inline int perf_allow_cpu(void) +{ + return perfmon_capable() ? 0 : -EACCES; +} +static inline int perf_allow_tracepoint(void) +{ + return perfmon_capable() ? 0 : -EPERM; +} + #endif /* !CONFIG_PERF_EVENTS */ #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL) -- cgit v1.2.3 From a03721ee484c6a5cbc58ece2cf6feaa2159761e7 Mon Sep 17 00:00:00 2001 From: Francois Dugast Date: Fri, 22 May 2026 11:25:31 +0200 Subject: gpu/buddy: Track per-order free blocks with a scoreboard Reporting per-order free block counts in drm_buddy_print() currently requires walking all rbtrees, which is O(n) over the total number of free blocks and holds the allocator lock for the duration. This becomes expensive on large VRAM heaps with many small free fragments. Maintain a free_scoreboard[] array indexed by order instead, so that the count for any order is always available in O(1). The scoreboard is kept accurate by hooking into the four places where a block's free state changes: mark_free(), mark_allocated(), mark_split(), and the sites in __gpu_buddy_free(), __force_merge(), and the four err_undo paths that call rbtree_remove() directly on free blocks without going through mark_*(). The print functions are simplified as a result: the rbtree traversal is replaced by a direct array lookup. v3: Update after introducing __gpu_buddy_undo_splits() helper v2: Update after fix for use-after-free in split_block() call sites Assisted-by: GitHub Copilot:claude-sonnet-4.6 Reviewed-by: Matthew Auld Link: https://lore.kernel.org/r/20260522092600.32818-5-francois.dugast@intel.com Signed-off-by: Francois Dugast --- drivers/gpu/buddy.c | 36 +++++++++++++++++++++--------------- drivers/gpu/drm/drm_buddy.c | 16 ++-------------- include/linux/gpu_buddy.h | 7 +++++++ 3 files changed, 30 insertions(+), 29 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c index 8654604b87a4..de18b63fef0a 100644 --- a/drivers/gpu/buddy.c +++ b/drivers/gpu/buddy.c @@ -193,6 +193,8 @@ static void mark_allocated(struct gpu_buddy *mm, block->header &= ~GPU_BUDDY_HEADER_STATE; block->header |= GPU_BUDDY_ALLOCATED; + mm->free_scoreboard[gpu_buddy_block_order(block)]--; + rbtree_remove(mm, block); } @@ -204,6 +206,8 @@ static void mark_free(struct gpu_buddy *mm, block->header &= ~GPU_BUDDY_HEADER_STATE; block->header |= GPU_BUDDY_FREE; + mm->free_scoreboard[gpu_buddy_block_order(block)]++; + tree = get_block_tree(block); rbtree_insert(mm, block, tree); } @@ -214,6 +218,8 @@ static void mark_split(struct gpu_buddy *mm, block->header &= ~GPU_BUDDY_HEADER_STATE; block->header |= GPU_BUDDY_SPLIT; + mm->free_scoreboard[gpu_buddy_block_order(block)]--; + rbtree_remove(mm, block); } @@ -271,6 +277,7 @@ static unsigned int __gpu_buddy_free(struct gpu_buddy *mm, } rbtree_remove(mm, buddy); + mm->free_scoreboard[gpu_buddy_block_order(buddy)]--; if (force_merge && gpu_buddy_block_is_clear(buddy)) mm->clear_avail -= gpu_buddy_block_size(mm, buddy); @@ -335,6 +342,7 @@ static int __force_merge(struct gpu_buddy *mm, iter = rb_prev(iter); rbtree_remove(mm, block); + mm->free_scoreboard[gpu_buddy_block_order(block)]--; if (gpu_buddy_block_is_clear(block)) mm->clear_avail -= gpu_buddy_block_size(mm, block); @@ -384,11 +392,17 @@ int gpu_buddy_init(struct gpu_buddy *mm, u64 size, u64 chunk_size) BUG_ON(mm->max_order > GPU_BUDDY_MAX_ORDER); + mm->free_scoreboard = kcalloc(mm->max_order + 1, + sizeof(*mm->free_scoreboard), + GFP_KERNEL); + if (!mm->free_scoreboard) + return -ENOMEM; + mm->free_trees = kmalloc_array(GPU_BUDDY_MAX_FREE_TREES, sizeof(*mm->free_trees), GFP_KERNEL); if (!mm->free_trees) - return -ENOMEM; + goto out_free_scoreboard; for_each_free_tree(i) { mm->free_trees[i] = kmalloc_array(mm->max_order + 1, @@ -450,6 +464,8 @@ out_free_tree: while (i--) kfree(mm->free_trees[i]); kfree(mm->free_trees); +out_free_scoreboard: + kfree(mm->free_scoreboard); return -ENOMEM; } EXPORT_SYMBOL(gpu_buddy_init); @@ -488,6 +504,7 @@ void gpu_buddy_fini(struct gpu_buddy *mm) kfree(mm->free_trees[i]); kfree(mm->free_trees); kfree(mm->roots); + kfree(mm->free_scoreboard); } EXPORT_SYMBOL(gpu_buddy_fini); @@ -659,6 +676,7 @@ static void __gpu_buddy_undo_splits(struct gpu_buddy *mm, (gpu_buddy_block_is_free(block) && gpu_buddy_block_is_free(buddy))) { rbtree_remove(mm, block); + mm->free_scoreboard[gpu_buddy_block_order(block)]--; __gpu_buddy_free(mm, block, false); } } @@ -1487,21 +1505,9 @@ void gpu_buddy_print(struct gpu_buddy *mm) 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++; - } - } + u64 count = mm->free_scoreboard[order]; + u64 free = count * (mm->chunk_size << order); - free = count * (mm->chunk_size << order); if (free < SZ_1M) pr_info("order-%2d free: %8llu KiB, blocks: %llu\n", order, free >> 10, count); diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index faa025498de4..eef995e08a37 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -47,23 +47,11 @@ void drm_buddy_print(struct gpu_buddy *mm, struct drm_printer *p) 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++; - } - } + u64 count = mm->free_scoreboard[order]; + u64 free = count * (mm->chunk_size << order); drm_printf(p, "order-%2d ", order); - free = count * (mm->chunk_size << order); if (free < SZ_1M) drm_printf(p, "free: %8llu KiB", free >> 10); else diff --git a/include/linux/gpu_buddy.h b/include/linux/gpu_buddy.h index 71941a039648..a28f7d7637ca 100644 --- a/include/linux/gpu_buddy.h +++ b/include/linux/gpu_buddy.h @@ -173,6 +173,13 @@ struct gpu_buddy { * that fits in the remaining space. */ struct gpu_buddy_block **roots; + /* + * Per-order free block scoreboard: free_scoreboard[order] holds the + * number of blocks of that order currently in the free state. + * Incremented in mark_free(), decremented wherever rbtree_remove() is + * called on a free block. + */ + u64 *free_scoreboard; /* public: */ unsigned int n_roots; unsigned int max_order; -- cgit v1.2.3 From 25d912475e8b734ac7bf1880920b6b42514e9472 Mon Sep 17 00:00:00 2001 From: Francois Dugast Date: Fri, 22 May 2026 11:25:32 +0200 Subject: gpu/buddy: Track per-order used blocks with a scoreboard Extend the scoreboard approach from the previous commit to used blocks, so drm_buddy_print() can report per-order allocation pressure in O(1). Unlike free blocks, an allocated block can leave the allocated state through mark_free() (normal free and gpu_buddy_block_trim()) or be consumed directly by gpu_block_free() during coalescing. Both sites are guarded by gpu_buddy_block_is_allocated() and paired with the increment in mark_allocated(). v3: - Assert scoreboard is empty at fini(), as sanity check (Matthew Auld) v2: - Update after fix for use-after-free in split_block() call sites - Change goto label to out_free_used_scoreboard for clarity - Make drm_buddy_print() and gpu_buddy_print() symmetric for used and free Assisted-by: GitHub Copilot:claude-sonnet-4.6 Reviewed-by: Matthew Auld Link: https://lore.kernel.org/r/20260522092600.32818-6-francois.dugast@intel.com Signed-off-by: Francois Dugast --- drivers/gpu/buddy.c | 42 ++++++++++++++++++++++++++++++++---------- drivers/gpu/drm/drm_buddy.c | 18 ++++++++++++------ include/linux/gpu_buddy.h | 8 ++++++++ 3 files changed, 52 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c index de18b63fef0a..dc81fe0301ce 100644 --- a/drivers/gpu/buddy.c +++ b/drivers/gpu/buddy.c @@ -194,6 +194,7 @@ static void mark_allocated(struct gpu_buddy *mm, block->header |= GPU_BUDDY_ALLOCATED; mm->free_scoreboard[gpu_buddy_block_order(block)]--; + mm->used_scoreboard[gpu_buddy_block_order(block)]++; rbtree_remove(mm, block); } @@ -203,6 +204,9 @@ static void mark_free(struct gpu_buddy *mm, { enum gpu_buddy_free_tree tree; + if (gpu_buddy_block_is_allocated(block)) + mm->used_scoreboard[gpu_buddy_block_order(block)]--; + block->header &= ~GPU_BUDDY_HEADER_STATE; block->header |= GPU_BUDDY_FREE; @@ -281,6 +285,9 @@ static unsigned int __gpu_buddy_free(struct gpu_buddy *mm, if (force_merge && gpu_buddy_block_is_clear(buddy)) mm->clear_avail -= gpu_buddy_block_size(mm, buddy); + if (gpu_buddy_block_is_allocated(block)) + mm->used_scoreboard[gpu_buddy_block_order(block)]--; + gpu_block_free(mm, block); gpu_block_free(mm, buddy); @@ -398,11 +405,17 @@ int gpu_buddy_init(struct gpu_buddy *mm, u64 size, u64 chunk_size) if (!mm->free_scoreboard) return -ENOMEM; + mm->used_scoreboard = kcalloc(mm->max_order + 1, + sizeof(*mm->used_scoreboard), + GFP_KERNEL); + if (!mm->used_scoreboard) + goto out_free_free_scoreboard; + mm->free_trees = kmalloc_array(GPU_BUDDY_MAX_FREE_TREES, sizeof(*mm->free_trees), GFP_KERNEL); if (!mm->free_trees) - goto out_free_scoreboard; + goto out_free_used_scoreboard; for_each_free_tree(i) { mm->free_trees[i] = kmalloc_array(mm->max_order + 1, @@ -464,7 +477,9 @@ out_free_tree: while (i--) kfree(mm->free_trees[i]); kfree(mm->free_trees); -out_free_scoreboard: +out_free_used_scoreboard: + kfree(mm->used_scoreboard); +out_free_free_scoreboard: kfree(mm->free_scoreboard); return -ENOMEM; } @@ -500,11 +515,15 @@ void gpu_buddy_fini(struct gpu_buddy *mm) gpu_buddy_assert(mm->avail == mm->size); + for (i = 0; i <= mm->max_order; ++i) + gpu_buddy_assert(!mm->used_scoreboard[i]); + for_each_free_tree(i) kfree(mm->free_trees[i]); kfree(mm->free_trees); kfree(mm->roots); kfree(mm->free_scoreboard); + kfree(mm->used_scoreboard); } EXPORT_SYMBOL(gpu_buddy_fini); @@ -1505,15 +1524,18 @@ void gpu_buddy_print(struct gpu_buddy *mm) mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); for (order = mm->max_order; order >= 0; order--) { - u64 count = mm->free_scoreboard[order]; - u64 free = count * (mm->chunk_size << order); - - if (free < SZ_1M) - pr_info("order-%2d free: %8llu KiB, blocks: %llu\n", - order, free >> 10, count); + u64 free_count = mm->free_scoreboard[order]; + u64 used_count = mm->used_scoreboard[order]; + u64 block_size = mm->chunk_size << order; + u64 free = free_count * block_size; + u64 used = used_count * block_size; + + if (block_size < SZ_1M) + pr_info("order-%2d free: %8llu KiB, used: %8llu KiB, free_blocks: %llu, used_blocks: %llu\n", + order, free >> 10, used >> 10, free_count, used_count); else - pr_info("order-%2d free: %8llu MiB, blocks: %llu\n", - order, free >> 20, count); + pr_info("order-%2d free: %8llu MiB, used: %8llu MiB, free_blocks: %llu, used_blocks: %llu\n", + order, free >> 20, used >> 20, free_count, used_count); } } EXPORT_SYMBOL(gpu_buddy_print); diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index eef995e08a37..1536e59c6fe7 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -47,17 +47,23 @@ void drm_buddy_print(struct gpu_buddy *mm, struct drm_printer *p) mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); for (order = mm->max_order; order >= 0; order--) { - u64 count = mm->free_scoreboard[order]; - u64 free = count * (mm->chunk_size << order); + u64 free_count = mm->free_scoreboard[order]; + u64 used_count = mm->used_scoreboard[order]; + u64 block_size = mm->chunk_size << order; + u64 free = free_count * block_size; + u64 used = used_count * block_size; drm_printf(p, "order-%2d ", order); - if (free < SZ_1M) - drm_printf(p, "free: %8llu KiB", free >> 10); + if (block_size < SZ_1M) + drm_printf(p, "free: %8llu KiB, used: %8llu KiB", + free >> 10, used >> 10); else - drm_printf(p, "free: %8llu MiB", free >> 20); + drm_printf(p, "free: %8llu MiB, used: %8llu MiB", + free >> 20, used >> 20); - drm_printf(p, ", blocks: %llu\n", count); + drm_printf(p, ", free_blocks: %llu, used_blocks: %llu\n", + free_count, used_count); } } EXPORT_SYMBOL(drm_buddy_print); diff --git a/include/linux/gpu_buddy.h b/include/linux/gpu_buddy.h index a28f7d7637ca..e037714563d8 100644 --- a/include/linux/gpu_buddy.h +++ b/include/linux/gpu_buddy.h @@ -180,6 +180,14 @@ struct gpu_buddy { * called on a free block. */ u64 *free_scoreboard; + /* + * Per-order used block scoreboard: used_scoreboard[order] holds the + * number of blocks of that order currently in the allocated state. + * Incremented in mark_allocated(), decremented in mark_free() (guarded + * by gpu_buddy_block_is_allocated()) and in __gpu_buddy_free() when an + * allocated block is consumed directly during buddy coalescing. + */ + u64 *used_scoreboard; /* public: */ unsigned int n_roots; unsigned int max_order; -- cgit v1.2.3 From 98a6cabfd805d55a1b2c70b01923ec9b9bbc706a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 29 May 2026 16:01:23 +0200 Subject: lib/fonts: Look up glyph data with font_data_glyph_buf() Add font_data_glyph_buf() to retrieve a character's glyph data or NULL otherwise. Console fonts can currently contain 256 or 512 glyphs. The kernel-internal characters are of type char, unsigned short or unsigned int. Catch all of them by accepting unsigned int. Callers possibly have to cast from signed to unsigned types to reach all glyphs in a font. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Link: https://patch.msgid.link/20260529140759.529929-2-tzimmermann@suse.de --- include/linux/font.h | 3 +++ lib/fonts/fonts.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'include/linux') diff --git a/include/linux/font.h b/include/linux/font.h index 6845f02d739a..ea23b727388b 100644 --- a/include/linux/font.h +++ b/include/linux/font.h @@ -101,6 +101,9 @@ font_data_t *font_data_import(const struct console_font *font, unsigned int vpit void font_data_get(font_data_t *fd); bool font_data_put(font_data_t *fd); unsigned int font_data_size(font_data_t *fd); +const unsigned char *font_data_glyph_buf(font_data_t *fd, + unsigned int width, unsigned int vpitch, + unsigned int c); bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs); int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch); diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c index f5d5333450a0..4fc66722d00d 100644 --- a/lib/fonts/fonts.c +++ b/lib/fonts/fonts.c @@ -178,6 +178,37 @@ unsigned int font_data_size(font_data_t *fd) } EXPORT_SYMBOL_GPL(font_data_size); +static unsigned int font_data_num_glyphs(font_data_t *fd, unsigned int width, unsigned int height) +{ + return font_data_size(fd) / font_glyph_size(width, height); +} + +/** + * font_data_glyph_buf() - Returns the glyph for a specific character as raw bytes + * @fd: The font data + * @width: The glyph width in bits per scanline + * @vpitch: The number of scanlines per glyph + * @c: The character + * + * Glyphs start at fixed intervals within the font data. font_data_glyph_buf() + * returns the glyph shape of the specified character. If no such glyph + * exists in the font, it returns NULL. + * + * Returns: + * The character's raw glyph shape, or NULL if no glyph exists for the character. The + * provided buffer is read-only. + */ +const unsigned char *font_data_glyph_buf(font_data_t *fd, + unsigned int width, unsigned int vpitch, + unsigned int c) +{ + if (c >= font_data_num_glyphs(fd, width, vpitch)) + return NULL; + + return font_data_buf(fd) + font_glyph_size(width, vpitch) * c; +} +EXPORT_SYMBOL_GPL(font_data_glyph_buf); + /** * font_data_is_equal - Compares font data for equality * @lhs: Left-hand side font data -- cgit v1.2.3 From 2afdfc658f7a7e9ee2a67ec6663922da9c799c53 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Wed, 10 Jun 2026 12:52:48 -0700 Subject: sysfb: correct CONFIG_SYSFB_SIMPLEFB macro name in #endif comment A comment in incorrectly refers to CONFIG_SYSFB_SIMPLE instead of CONFIG_SYSFB_SIMPLEFB. Correct it. Discovered while searching for CONFIG_* symbols referenced in code but not defined in any Kconfig file. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Thomas Zimmermann Reviewed-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patch.msgid.link/20260610195248.19442-1-enelsonmoore@gmail.com --- include/linux/sysfb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h index 5226efde9ad4..ed23d6516223 100644 --- a/include/linux/sysfb.h +++ b/include/linux/sysfb.h @@ -118,7 +118,7 @@ struct platform_device *sysfb_create_simplefb(const struct screen_info *si, const struct simplefb_platform_data *mode, struct device *parent); -#else /* CONFIG_SYSFB_SIMPLE */ +#else /* CONFIG_SYSFB_SIMPLEFB */ static inline bool sysfb_parse_mode(const struct screen_info *si, struct simplefb_platform_data *mode) @@ -133,6 +133,6 @@ static inline struct platform_device *sysfb_create_simplefb(const struct screen_ return ERR_PTR(-EINVAL); } -#endif /* CONFIG_SYSFB_SIMPLE */ +#endif /* CONFIG_SYSFB_SIMPLEFB */ #endif /* _LINUX_SYSFB_H */ -- cgit v1.2.3 From 9370a5c664e8d95561cc9a418e499a15bf2bc1a3 Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 23 Jun 2026 17:23:04 +0200 Subject: dma-buf: rename dma_fence_enable_sw_signaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping the _sw_ part from the names was proposed multiple times now and IIRC people generally agreed with the idea already. The function requests a fence to signal and triggers some sort of HW interaction on most backends. So this is not really software related at all and the callback is already just named enable_signaling as well. Just streamline that and use a consistent name everywhere. Assisted-by: Claude Sonet 4 Signed-off-by: Christian König Reviewed-by: Matthew Brost Reviewed-by: Tvrtko Ursulin Link: https://lore.kernel.org/r/20260624122917.2483-2-christian.koenig@amd.com --- drivers/dma-buf/dma-fence.c | 8 ++--- drivers/dma-buf/st-dma-fence-chain.c | 4 +-- drivers/dma-buf/st-dma-fence-unwrap.c | 42 ++++++++++++------------ drivers/dma-buf/st-dma-fence.c | 16 ++++----- drivers/dma-buf/st-dma-resv.c | 10 +++--- drivers/gpu/drm/i915/i915_active.c | 2 +- drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c | 2 +- drivers/gpu/drm/ttm/ttm_bo.c | 2 +- drivers/gpu/drm/xe/xe_bo.c | 2 +- drivers/gpu/drm/xe/xe_sched_job.c | 2 +- drivers/gpu/drm/xe/xe_svm.c | 2 +- drivers/gpu/drm/xe/xe_userptr.c | 2 +- drivers/gpu/drm/xe/xe_vm.c | 4 +-- include/linux/dma-fence.h | 4 +-- 14 files changed, 51 insertions(+), 51 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index c7ea1e75d38a..0ec81a568bbd 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -534,7 +534,7 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout) __dma_fence_might_wait(); - dma_fence_enable_sw_signaling(fence); + dma_fence_enable_signaling(fence); rcu_read_lock(); ops = rcu_dereference(fence->ops); @@ -656,14 +656,14 @@ static bool __dma_fence_enable_signaling(struct dma_fence *fence) } /** - * dma_fence_enable_sw_signaling - enable signaling on fence + * dma_fence_enable_signaling - enable signaling on fence * @fence: the fence to enable * * This will request for sw signaling to be enabled, to make the fence * complete as soon as possible. This calls &dma_fence_ops.enable_signaling * internally. */ -void dma_fence_enable_sw_signaling(struct dma_fence *fence) +void dma_fence_enable_signaling(struct dma_fence *fence) { unsigned long flags; @@ -671,7 +671,7 @@ void dma_fence_enable_sw_signaling(struct dma_fence *fence) __dma_fence_enable_signaling(fence); dma_fence_unlock_irqrestore(fence, flags); } -EXPORT_SYMBOL(dma_fence_enable_sw_signaling); +EXPORT_SYMBOL(dma_fence_enable_signaling); /** * dma_fence_add_callback - add a callback to be called when the fence diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c index a3023d3fedc9..e0d9b69bfa76 100644 --- a/drivers/dma-buf/st-dma-fence-chain.c +++ b/drivers/dma-buf/st-dma-fence-chain.c @@ -82,7 +82,7 @@ static void test_sanitycheck(struct kunit *test) chain = mock_chain(NULL, f, 1); if (chain) - dma_fence_enable_sw_signaling(chain); + dma_fence_enable_signaling(chain); else KUNIT_FAIL(test, "Failed to create chain"); @@ -139,7 +139,7 @@ static int fence_chains_init(struct fence_chains *fc, unsigned int count, fc->tail = fc->chains[i]; - dma_fence_enable_sw_signaling(fc->chains[i]); + dma_fence_enable_signaling(fc->chains[i]); } fc->chain_length = i; diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c index 4e7ee25372ba..4d9d313b460c 100644 --- a/drivers/dma-buf/st-dma-fence-unwrap.c +++ b/drivers/dma-buf/st-dma-fence-unwrap.c @@ -103,7 +103,7 @@ static void test_sanitycheck(struct kunit *test) f = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); array = mock_array(1, f); KUNIT_ASSERT_NOT_NULL(test, array); @@ -122,7 +122,7 @@ static void test_unwrap_array(struct kunit *test) f1 = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = mock_fence(); if (!f2) { @@ -131,7 +131,7 @@ static void test_unwrap_array(struct kunit *test) return; } - dma_fence_enable_sw_signaling(f2); + dma_fence_enable_signaling(f2); array = mock_array(2, f1, f2); KUNIT_ASSERT_NOT_NULL(test, array); @@ -160,7 +160,7 @@ static void test_unwrap_chain(struct kunit *test) f1 = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = mock_fence(); if (!f2) { @@ -169,7 +169,7 @@ static void test_unwrap_chain(struct kunit *test) return; } - dma_fence_enable_sw_signaling(f2); + dma_fence_enable_signaling(f2); chain = mock_chain(f1, f2); KUNIT_ASSERT_NOT_NULL(test, chain); @@ -198,7 +198,7 @@ static void test_unwrap_chain_array(struct kunit *test) f1 = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = mock_fence(); if (!f2) { @@ -207,7 +207,7 @@ static void test_unwrap_chain_array(struct kunit *test) return; } - dma_fence_enable_sw_signaling(f2); + dma_fence_enable_signaling(f2); array = mock_array(2, f1, f2); KUNIT_ASSERT_NOT_NULL(test, array); @@ -239,7 +239,7 @@ static void test_unwrap_merge(struct kunit *test) f1 = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = mock_fence(); if (!f2) { @@ -247,7 +247,7 @@ static void test_unwrap_merge(struct kunit *test) goto error_put_f1; } - dma_fence_enable_sw_signaling(f2); + dma_fence_enable_signaling(f2); f3 = dma_fence_unwrap_merge(f1, f2); if (!f3) { @@ -285,7 +285,7 @@ static void test_unwrap_merge_duplicate(struct kunit *test) f1 = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = dma_fence_unwrap_merge(f1, f1); if (!f2) { @@ -322,7 +322,7 @@ static void test_unwrap_merge_seqno(struct kunit *test) f1 = __mock_fence(ctx[1], 1); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = __mock_fence(ctx[1], 2); if (!f2) { @@ -330,7 +330,7 @@ static void test_unwrap_merge_seqno(struct kunit *test) goto error_put_f1; } - dma_fence_enable_sw_signaling(f2); + dma_fence_enable_signaling(f2); f3 = __mock_fence(ctx[0], 1); if (!f3) { @@ -338,7 +338,7 @@ static void test_unwrap_merge_seqno(struct kunit *test) goto error_put_f2; } - dma_fence_enable_sw_signaling(f3); + dma_fence_enable_signaling(f3); f4 = dma_fence_unwrap_merge(f1, f2, f3); if (!f4) { @@ -378,7 +378,7 @@ static void test_unwrap_merge_order(struct kunit *test) f1 = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = mock_fence(); if (!f2) { @@ -387,7 +387,7 @@ static void test_unwrap_merge_order(struct kunit *test) return; } - dma_fence_enable_sw_signaling(f2); + dma_fence_enable_signaling(f2); a1 = mock_array(2, f1, f2); KUNIT_ASSERT_NOT_NULL(test, a1); @@ -442,7 +442,7 @@ static void test_unwrap_merge_complex(struct kunit *test) f1 = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = mock_fence(); if (!f2) { @@ -450,7 +450,7 @@ static void test_unwrap_merge_complex(struct kunit *test) goto error_put_f1; } - dma_fence_enable_sw_signaling(f2); + dma_fence_enable_signaling(f2); f3 = dma_fence_unwrap_merge(f1, f2); if (!f3) { @@ -510,7 +510,7 @@ static void test_unwrap_merge_complex_seqno(struct kunit *test) f1 = __mock_fence(ctx[0], 2); KUNIT_ASSERT_NOT_NULL(test, f1); - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); f2 = __mock_fence(ctx[1], 1); if (!f2) { @@ -518,7 +518,7 @@ static void test_unwrap_merge_complex_seqno(struct kunit *test) goto error_put_f1; } - dma_fence_enable_sw_signaling(f2); + dma_fence_enable_signaling(f2); f3 = __mock_fence(ctx[0], 1); if (!f3) { @@ -526,7 +526,7 @@ static void test_unwrap_merge_complex_seqno(struct kunit *test) goto error_put_f2; } - dma_fence_enable_sw_signaling(f3); + dma_fence_enable_signaling(f3); f4 = __mock_fence(ctx[1], 2); if (!f4) { @@ -534,7 +534,7 @@ static void test_unwrap_merge_complex_seqno(struct kunit *test) goto error_put_f3; } - dma_fence_enable_sw_signaling(f4); + dma_fence_enable_signaling(f4); f5 = mock_array(2, dma_fence_get(f1), dma_fence_get(f2)); if (!f5) { diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c index 499272229696..856d0d302a5d 100644 --- a/drivers/dma-buf/st-dma-fence.c +++ b/drivers/dma-buf/st-dma-fence.c @@ -42,7 +42,7 @@ static void test_sanitycheck(struct kunit *test) f = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); dma_fence_signal(f); dma_fence_put(f); @@ -55,7 +55,7 @@ static void test_signaling(struct kunit *test) f = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); if (dma_fence_is_signaled(f)) { KUNIT_FAIL(test, "Fence unexpectedly signaled on creation"); @@ -127,7 +127,7 @@ static void test_late_add_callback(struct kunit *test) f = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); dma_fence_signal(f); @@ -209,7 +209,7 @@ static void test_status(struct kunit *test) f = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); if (dma_fence_get_status(f)) { KUNIT_FAIL(test, "Fence unexpectedly has signaled status on creation"); @@ -233,7 +233,7 @@ static void test_error(struct kunit *test) f = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); dma_fence_set_error(f, -EIO); @@ -260,7 +260,7 @@ static void test_wait(struct kunit *test) f = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); if (dma_fence_wait_timeout(f, false, 0) != 0) { KUNIT_FAIL(test, "Wait reported complete before being signaled"); @@ -300,7 +300,7 @@ static void test_wait_timeout(struct kunit *test) wt.f = mock_fence(); KUNIT_ASSERT_NOT_NULL(test, wt.f); - dma_fence_enable_sw_signaling(wt.f); + dma_fence_enable_signaling(wt.f); if (dma_fence_wait_timeout(wt.f, false, 1) != 0) { KUNIT_FAIL(test, "Wait reported complete before being signaled"); @@ -379,7 +379,7 @@ static int thread_signal_callback(void *arg) break; } - dma_fence_enable_sw_signaling(f1); + dma_fence_enable_signaling(f1); rcu_assign_pointer(t->fences[t->id], f1); smp_wmb(); diff --git a/drivers/dma-buf/st-dma-resv.c b/drivers/dma-buf/st-dma-resv.c index 95a4becdb892..0b96136bbd54 100644 --- a/drivers/dma-buf/st-dma-resv.c +++ b/drivers/dma-buf/st-dma-resv.c @@ -48,7 +48,7 @@ static void test_sanitycheck(struct kunit *test) f = alloc_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); dma_fence_signal(f); dma_fence_put(f); @@ -73,7 +73,7 @@ static void test_signaling(struct kunit *test) f = alloc_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); @@ -117,7 +117,7 @@ static void test_for_each(struct kunit *test) f = alloc_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); @@ -176,7 +176,7 @@ static void test_for_each_unlocked(struct kunit *test) f = alloc_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); @@ -246,7 +246,7 @@ static void test_get_fences(struct kunit *test) f = alloc_fence(); KUNIT_ASSERT_NOT_NULL(test, f); - dma_fence_enable_sw_signaling(f); + dma_fence_enable_signaling(f); dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c index 5cb7a72774a0..e7632c1ff4be 100644 --- a/drivers/gpu/drm/i915/i915_active.c +++ b/drivers/gpu/drm/i915/i915_active.c @@ -543,7 +543,7 @@ static void enable_signaling(struct i915_active_fence *active) if (!fence) return; - dma_fence_enable_sw_signaling(fence); + dma_fence_enable_signaling(fence); dma_fence_put(fence); } diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c index 2db221f6fc3a..56ad8ef32584 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c +++ b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c @@ -69,7 +69,7 @@ static void dma_resv_kunit_active_fence_init(struct kunit *test, struct dma_fence *fence; fence = alloc_mock_fence(test); - dma_fence_enable_sw_signaling(fence); + dma_fence_enable_signaling(fence); dma_resv_lock(resv, NULL); dma_resv_reserve_fences(resv, 1); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index bcd76f6bb7f0..3980f376e3ba 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -224,7 +224,7 @@ static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo) dma_resv_iter_begin(&cursor, resv, DMA_RESV_USAGE_BOOKKEEP); dma_resv_for_each_fence_unlocked(&cursor, fence) - dma_fence_enable_sw_signaling(fence); + dma_fence_enable_signaling(fence); dma_resv_iter_end(&cursor); } diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 4c80bac67622..85e6d9a0f575 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -670,7 +670,7 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo, dma_resv_iter_begin(&cursor, bo->ttm.base.resv, DMA_RESV_USAGE_BOOKKEEP); dma_resv_for_each_fence_unlocked(&cursor, fence) - dma_fence_enable_sw_signaling(fence); + dma_fence_enable_signaling(fence); dma_resv_iter_end(&cursor); } diff --git a/drivers/gpu/drm/xe/xe_sched_job.c b/drivers/gpu/drm/xe/xe_sched_job.c index ae5b38b2a884..a4fa00632a30 100644 --- a/drivers/gpu/drm/xe/xe_sched_job.c +++ b/drivers/gpu/drm/xe/xe_sched_job.c @@ -214,7 +214,7 @@ void xe_sched_job_set_error(struct xe_sched_job *job, int error) trace_xe_sched_job_set_error(job); - dma_fence_enable_sw_signaling(job->fence); + dma_fence_enable_signaling(job->fence); xe_hw_fence_irq_run(job->q->fence_irq); } diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index e1651e70c8f0..dba73786d82a 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -1090,7 +1090,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, dma_resv_wait_timeout(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL, false, MAX_SCHEDULE_TIMEOUT); else if (pre_migrate_fence) - dma_fence_enable_sw_signaling(pre_migrate_fence); + dma_fence_enable_signaling(pre_migrate_fence); } drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm, diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c index 6761005c0b90..2e45e42c648f 100644 --- a/drivers/gpu/drm/xe/xe_userptr.c +++ b/drivers/gpu/drm/xe/xe_userptr.c @@ -180,7 +180,7 @@ xe_vma_userptr_invalidate_pass1(struct xe_vm *vm, struct xe_userptr_vma *uvma) dma_resv_iter_begin(&cursor, xe_vm_resv(vm), DMA_RESV_USAGE_BOOKKEEP); dma_resv_for_each_fence_unlocked(&cursor, fence) { - dma_fence_enable_sw_signaling(fence); + dma_fence_enable_signaling(fence); if (signaled && !dma_fence_is_signaled(fence)) signaled = false; } diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 080c2fff0e95..73ac031ffb04 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -256,7 +256,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q) */ wait = __xe_vm_userptr_needs_repin(vm) || preempt_fences_waiting(vm); if (wait) - dma_fence_enable_sw_signaling(pfence); + dma_fence_enable_signaling(pfence); xe_svm_notifier_unlock(vm); @@ -287,7 +287,7 @@ void xe_vm_remove_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q) --vm->preempt.num_exec_queues; } if (q->lr.pfence) { - dma_fence_enable_sw_signaling(q->lr.pfence); + dma_fence_enable_signaling(q->lr.pfence); dma_fence_put(q->lr.pfence); q->lr.pfence = NULL; } diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index b52ab692b22e..158cd609f103 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -448,7 +448,7 @@ int dma_fence_add_callback(struct dma_fence *fence, dma_fence_func_t func); bool dma_fence_remove_callback(struct dma_fence *fence, struct dma_fence_cb *cb); -void dma_fence_enable_sw_signaling(struct dma_fence *fence); +void dma_fence_enable_signaling(struct dma_fence *fence); /** * DOC: Safe external access to driver provided object members @@ -534,7 +534,7 @@ dma_fence_is_signaled_locked(struct dma_fence *fence) * Returns true if the fence was already signaled, false if not. Since this * function doesn't enable signaling, it is not guaranteed to ever return * true if dma_fence_add_callback(), dma_fence_wait() or - * dma_fence_enable_sw_signaling() haven't been called before. + * dma_fence_enable_signaling() haven't been called before. * * It's recommended for seqno fences to call dma_fence_signal when the * operation is complete, it makes it possible to prevent issues from -- cgit v1.2.3 From 44d19b8a7548aa25cbc6ebd5f27e958f7142c36b Mon Sep 17 00:00:00 2001 From: Shahyan Soltani Date: Tue, 30 Jun 2026 12:04:01 -0400 Subject: dma_buf: change unsigned int and int types into size_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The num_fences, count, i, and j variables in dma_fence_dedup_array() and __dma_fence_unwrap_merge() have inconsistent integer types, mixing both unsigned int and int. Use type size_t consistently for these instead, and update the return type of dma_fence_dedup_array() accordingly. Signed-off-by: Shahyan Soltani Suggested-by: Philipp Stanner Link: https://lore.kernel.org/r/20260630160401.67544-1-shahyan.soltani@amd.com Reviewed-by: Philipp Stanner Reviewed-by: Christian König Signed-off-by: Christian König --- drivers/dma-buf/dma-fence-unwrap.c | 8 ++++---- include/linux/dma-fence-unwrap.h | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c index 53bb40e70b27..65e87d263c3a 100644 --- a/drivers/dma-buf/dma-fence-unwrap.c +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -93,9 +93,9 @@ static int fence_cmp(const void *_a, const void *_b) * * Return: Number of unique fences remaining in the array. */ -int dma_fence_dedup_array(struct dma_fence **fences, int num_fences) +size_t dma_fence_dedup_array(struct dma_fence **fences, size_t num_fences) { - int i, j; + size_t i, j; sort(fences, num_fences, sizeof(*fences), fence_cmp, NULL); @@ -115,14 +115,14 @@ int dma_fence_dedup_array(struct dma_fence **fences, int num_fences) EXPORT_SYMBOL_GPL(dma_fence_dedup_array); /* Implementation for the dma_fence_merge() marco, don't use directly */ -struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, +struct dma_fence *__dma_fence_unwrap_merge(size_t num_fences, struct dma_fence **fences, struct dma_fence_unwrap *iter) { struct dma_fence *tmp, *unsignaled = NULL, **array; struct dma_fence_array *result; ktime_t timestamp; - int i, count; + size_t i, count; count = 0; timestamp = ns_to_ktime(0); diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h index 62df222fe0f1..7bfacdf79de2 100644 --- a/include/linux/dma-fence-unwrap.h +++ b/include/linux/dma-fence-unwrap.h @@ -8,6 +8,8 @@ #ifndef __LINUX_DMA_FENCE_UNWRAP_H #define __LINUX_DMA_FENCE_UNWRAP_H +#include + struct dma_fence; /** @@ -48,11 +50,11 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor); for (fence = dma_fence_unwrap_first(head, cursor); fence; \ fence = dma_fence_unwrap_next(cursor)) -struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, +struct dma_fence *__dma_fence_unwrap_merge(size_t num_fences, struct dma_fence **fences, struct dma_fence_unwrap *cursors); -int dma_fence_dedup_array(struct dma_fence **array, int num_fences); +size_t dma_fence_dedup_array(struct dma_fence **array, size_t num_fences); /** * dma_fence_unwrap_merge - unwrap and merge fences -- cgit v1.2.3 From 7cffd051ae546e8644bf9bf7410b63541f666845 Mon Sep 17 00:00:00 2001 From: Zhi Wang Date: Wed, 22 Jul 2026 10:39:08 +0300 Subject: PCI/IOV: Return unsigned int from pci_sriov_get_totalvfs() pci_sriov_get_totalvfs() reports a VF count, not an errno-style status. It returns 0 when SR-IOV is unavailable or the device is not a PF, and otherwise returns the PF's driver_max_VFs value. driver_max_VFs is stored as a u16 in struct pci_sriov. It is derived from the SR-IOV TotalVFs field or from a driver-provided limit, so the implementation cannot return a negative value. Change the declaration, CONFIG_PCI_IOV stub, and implementation to return unsigned int. Suggested-by: Alexandre Courbot Reviewed-by: Alexandre Courbot Acked-by: Bjorn Helgaas Cc: Bjorn Helgaas Cc: David Laight Cc: Gary Guo Cc: linux-pci@vger.kernel.org Link: https://lore.kernel.org/all/DJHPRE4TGGT8.BUTMYOF5YE05@nvidia.com/ Signed-off-by: Zhi Wang Link: https://patch.msgid.link/20260722073913.1807677-2-zhiw@nvidia.com Signed-off-by: Danilo Krummrich --- drivers/pci/iov.c | 2 +- include/linux/pci.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index b0d24839c084..9d408fb8ac25 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -1283,7 +1283,7 @@ EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs); * SRIOV capability value of TotalVFs or the value of driver_max_VFs * if the driver reduced it. Otherwise 0. */ -int pci_sriov_get_totalvfs(struct pci_dev *dev) +unsigned int pci_sriov_get_totalvfs(struct pci_dev *dev) { if (!dev->is_physfn) return 0; diff --git a/include/linux/pci.h b/include/linux/pci.h index ebb5b9d76360..2b9c61de5f67 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2569,7 +2569,7 @@ void pci_iov_remove_virtfn(struct pci_dev *dev, int id); int pci_num_vf(struct pci_dev *dev); int pci_vfs_assigned(struct pci_dev *dev); int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs); -int pci_sriov_get_totalvfs(struct pci_dev *dev); +unsigned int pci_sriov_get_totalvfs(struct pci_dev *dev); int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn); resource_size_t pci_iov_resource_size(const struct pci_dev *dev, int resno); int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size); @@ -2622,7 +2622,7 @@ static inline int pci_vfs_assigned(struct pci_dev *dev) { return 0; } static inline int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) { return 0; } -static inline int pci_sriov_get_totalvfs(struct pci_dev *dev) +static inline unsigned int pci_sriov_get_totalvfs(struct pci_dev *dev) { return 0; } #define pci_sriov_configure_simple NULL static inline resource_size_t pci_iov_resource_size(const struct pci_dev *dev, -- cgit v1.2.3 From dd517e49a3123f868151ff1a193add8e10ae69ba Mon Sep 17 00:00:00 2001 From: Natalie Vock Date: Tue, 4 Aug 2026 10:25:16 +0200 Subject: cgroup/dmem: Add queries for protection values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Callers can use this feedback to be more aggressive in making space for allocations of a cgroup if they know it is protected. These are counterparts to memcg's mem_cgroup_below_{min,low}. Reviewed-by: Maarten Lankhorst Reviewed-by: Timur Kristóf Signed-off-by: Natalie Vock Link: https://patch.msgid.link/20260804-dmemcg-aggressive-protect-v8-1-07af96681bf8@gmx.de --- include/linux/cgroup_dmem.h | 16 ++++++++++++ kernel/cgroup/dmem.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) (limited to 'include/linux') diff --git a/include/linux/cgroup_dmem.h b/include/linux/cgroup_dmem.h index dd4869f1d736..1a88cd0c9eb0 100644 --- a/include/linux/cgroup_dmem.h +++ b/include/linux/cgroup_dmem.h @@ -24,6 +24,10 @@ void dmem_cgroup_uncharge(struct dmem_cgroup_pool_state *pool, u64 size); bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool, struct dmem_cgroup_pool_state *test_pool, bool ignore_low, bool *ret_hit_low); +bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root, + struct dmem_cgroup_pool_state *test); +bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, + struct dmem_cgroup_pool_state *test); void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool); #else @@ -59,6 +63,18 @@ bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool, return true; } +static inline bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root, + struct dmem_cgroup_pool_state *test) +{ + return false; +} + +static inline bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, + struct dmem_cgroup_pool_state *test) +{ + return false; +} + static inline void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool) { } diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c index 39930c59cb76..9df3b33c6504 100644 --- a/kernel/cgroup/dmem.c +++ b/kernel/cgroup/dmem.c @@ -700,6 +700,68 @@ err: } EXPORT_SYMBOL_GPL(dmem_cgroup_try_charge); +/** + * dmem_cgroup_below_min() - Tests whether current usage is within min limit. + * + * @root: Root of the subtree to calculate protection for, or NULL to calculate global protection. + * @test: The pool to test the usage/min limit of. + * + * Return: true if usage is below min and the cgroup is protected, false otherwise. + */ +bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root, + struct dmem_cgroup_pool_state *test) +{ + if (root == test || !pool_parent(test)) + return false; + + if (!root) { + for (root = test; pool_parent(root); root = pool_parent(root)) + {} + } + + /* + * In mem_cgroup_below_min(), the memcg pendant, this call is missing. + * mem_cgroup_below_min() gets called during traversal of the cgroup tree, where + * protection is already calculated as part of the traversal. dmem cgroup eviction + * does not traverse the cgroup tree, so we need to recalculate effective protection + * here. + */ + dmem_cgroup_calculate_protection(root, test); + return page_counter_read(&test->cnt) <= READ_ONCE(test->cnt.emin); +} +EXPORT_SYMBOL_GPL(dmem_cgroup_below_min); + +/** + * dmem_cgroup_below_low() - Tests whether current usage is within low limit. + * + * @root: Root of the subtree to calculate protection for, or NULL to calculate global protection. + * @test: The pool to test the usage/low limit of. + * + * Return: true if usage is below low and the cgroup is protected, false otherwise. + */ +bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, + struct dmem_cgroup_pool_state *test) +{ + if (root == test || !pool_parent(test)) + return false; + + if (!root) { + for (root = test; pool_parent(root); root = pool_parent(root)) + {} + } + + /* + * In mem_cgroup_below_low(), the memcg pendant, this call is missing. + * mem_cgroup_below_low() gets called during traversal of the cgroup tree, where + * protection is already calculated as part of the traversal. dmem cgroup eviction + * does not traverse the cgroup tree, so we need to recalculate effective protection + * here. + */ + dmem_cgroup_calculate_protection(root, test); + return page_counter_read(&test->cnt) <= READ_ONCE(test->cnt.elow); +} +EXPORT_SYMBOL_GPL(dmem_cgroup_below_low); + static int dmem_cgroup_region_capacity_show(struct seq_file *sf, void *v) { struct dmem_cgroup_region *region; -- cgit v1.2.3 From 34f3e259925382cd87187dd426d3918379c6144e Mon Sep 17 00:00:00 2001 From: Natalie Vock Date: Tue, 4 Aug 2026 10:25:17 +0200 Subject: cgroup,cgroup/dmem: Add (dmem_)cgroup_common_ancestor helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps to find a common subtree of two resources, which is important when determining whether it's helpful to evict one resource in favor of another. To facilitate this, add a common helper to find the ancestor of two cgroups using each cgroup's ancestor array. Tested-by: Thadeu Lima de Souza Cascardo Reviewed-by: Maarten Lankhorst Reviewed-by: Timur Kristóf Signed-off-by: Natalie Vock Link: https://patch.msgid.link/20260804-dmemcg-aggressive-protect-v8-2-07af96681bf8@gmx.de --- include/linux/cgroup.h | 21 +++++++++++++++++++++ include/linux/cgroup_dmem.h | 9 +++++++++ kernel/cgroup/dmem.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index f2aa46a4f871..83a17ded1c51 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -623,6 +623,27 @@ static inline struct cgroup *cgroup_ancestor(struct cgroup *cgrp, return cgrp->ancestors[ancestor_level]; } +/** + * cgroup_common_ancestor - find common ancestor of two cgroups + * @a: first cgroup to find common ancestor of + * @b: second cgroup to find common ancestor of + * + * Find the first cgroup that is an ancestor of both @a and @b, if it exists + * and return a pointer to it. If such a cgroup doesn't exist, return NULL. + * + * This function is safe to call as long as both @a and @b are accessible. + */ +static inline struct cgroup *cgroup_common_ancestor(struct cgroup *a, + struct cgroup *b) +{ + int level; + + for (level = min(a->level, b->level); level >= 0; level--) + if (a->ancestors[level] == b->ancestors[level]) + return a->ancestors[level]; + return NULL; +} + /** * task_under_cgroup_hierarchy - test task's membership of cgroup ancestry * @task: the task to be tested diff --git a/include/linux/cgroup_dmem.h b/include/linux/cgroup_dmem.h index 1a88cd0c9eb0..9d72457c4cb9 100644 --- a/include/linux/cgroup_dmem.h +++ b/include/linux/cgroup_dmem.h @@ -28,6 +28,8 @@ bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root, struct dmem_cgroup_pool_state *test); bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, struct dmem_cgroup_pool_state *test); +struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a, + struct dmem_cgroup_pool_state *b); void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool); #else @@ -75,6 +77,13 @@ static inline bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, return false; } +static inline +struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a, + struct dmem_cgroup_pool_state *b) +{ + return NULL; +} + static inline void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool) { } diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c index 9df3b33c6504..1af08b0464b8 100644 --- a/kernel/cgroup/dmem.c +++ b/kernel/cgroup/dmem.c @@ -762,6 +762,48 @@ bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, } EXPORT_SYMBOL_GPL(dmem_cgroup_below_low); +/** + * dmem_cgroup_get_common_ancestor(): Find the first common ancestor of two pools. + * @a: First pool to find the common ancestor of. + * @b: First pool to find the common ancestor of. + * + * Return: The first pool that is a parent of both @a and @b, or NULL if either @a or @b are NULL, + * or if such a pool does not exist. A reference to the returned pool is grabbed and must be + * released by the caller when it is done using the pool. + */ +struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a, + struct dmem_cgroup_pool_state *b) +{ + struct cgroup *ancestor_cgroup; + struct cgroup_subsys_state *ancestor_css; + struct dmemcg_state *ancestor_dmemcs = NULL; + struct dmem_cgroup_pool_state *pool = NULL; + + if (!a || !b) + return NULL; + + ancestor_cgroup = cgroup_common_ancestor(a->cs->css.cgroup, b->cs->css.cgroup); + if (!ancestor_cgroup) + return NULL; + + rcu_read_lock(); + ancestor_css = cgroup_e_css(ancestor_cgroup, &dmem_cgrp_subsys); + if (css_tryget(ancestor_css)) + ancestor_dmemcs = css_to_dmemcs(ancestor_css); + rcu_read_unlock(); + + if (ancestor_dmemcs) { + pool = get_cg_pool_unlocked(css_to_dmemcs(ancestor_css), + a->region); + if (WARN_ON(IS_ERR(pool))) { + pool = NULL; + css_put(ancestor_css); + } + } + return pool; +} +EXPORT_SYMBOL_GPL(dmem_cgroup_get_common_ancestor); + static int dmem_cgroup_region_capacity_show(struct seq_file *sf, void *v) { struct dmem_cgroup_region *region; -- cgit v1.2.3 From 151ebbc20aa2365fa854a77432043b16606b5cfe Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Thu, 6 Aug 2026 11:06:25 +0530 Subject: drm/gpu: Add gpu_buddy_allocated_addr_to_block helper Add helper with primary purpose is to efficiently trace a specific physical memory address back to its corresponding TTM buffer object. v3: - use mm->chunk_size minimum allocation granularity (Arun) v2: - %s/gpu_buddy_addr_to_block/gpu_buddy_allocated_addr_to_block(MattA) - remove clear->avail and split nodes check(MattA) - Adapt lockdep(MattB) Signed-off-by: Tejas Upadhyay Cc: Arunpravin Paneer Selvam Cc: dri-devel@lists.freedesktop.org Reviewed-by: Arunpravin Paneer Selvam Signed-off-by: Arunpravin Paneer Selvam Link: https://patch.msgid.link/20260806053624.3215216-5-tejas.upadhyay@intel.com --- drivers/gpu/buddy.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/gpu_buddy.h | 2 ++ 2 files changed, 55 insertions(+) (limited to 'include/linux') diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c index dc81fe0301ce..4d5ac375a538 100644 --- a/drivers/gpu/buddy.c +++ b/drivers/gpu/buddy.c @@ -630,6 +630,59 @@ void gpu_buddy_free_block(struct gpu_buddy *mm, } EXPORT_SYMBOL(gpu_buddy_free_block); +/** + * gpu_buddy_allocated_addr_to_block - given relative address find the allocated block + * + * @mm: GPU buddy manager + * @addr: Relative address + * + * Returns: + * gpu_buddy_block on success, NULL or error code on failure + */ +struct gpu_buddy_block *gpu_buddy_allocated_addr_to_block(struct gpu_buddy *mm, u64 addr) +{ + struct gpu_buddy_block *block; + LIST_HEAD(dfs); + u64 end; + int i; + + gpu_buddy_driver_lock_held(mm); + + end = addr + mm->chunk_size - 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); + + block_start = gpu_buddy_block_offset(block); + block_end = block_start + gpu_buddy_block_size(mm, block) - 1; + + if (!overlaps(addr, end, block_start, block_end)) + continue; + + if (gpu_buddy_block_is_allocated(block)) + return block; + else if (gpu_buddy_block_is_free(block)) + return NULL; + + list_add(&block->right->tmp_link, &dfs); + list_add(&block->left->tmp_link, &dfs); + } while (1); + + return ERR_PTR(-ENXIO); +} +EXPORT_SYMBOL(gpu_buddy_allocated_addr_to_block); + static void __gpu_buddy_free_list(struct gpu_buddy *mm, struct list_head *objects, bool mark_clear, diff --git a/include/linux/gpu_buddy.h b/include/linux/gpu_buddy.h index e037714563d8..2c36124bb696 100644 --- a/include/linux/gpu_buddy.h +++ b/include/linux/gpu_buddy.h @@ -287,6 +287,8 @@ 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); +struct gpu_buddy_block *gpu_buddy_allocated_addr_to_block(struct gpu_buddy *mm, u64 addr); + void gpu_buddy_free_list(struct gpu_buddy *mm, struct list_head *objects, unsigned int flags); -- cgit v1.2.3 From e11640b9cea4e0c448df1d31b9e950fa52cf19af Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Sat, 25 Jul 2026 12:00:32 +0200 Subject: cgroup/dmem: Introduce struct dmem_cgroup_init for region initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the bare u64 size argument to dmem_cgroup_register_region() and drmm_cgroup_register_region() with a const struct dmem_cgroup_init * pointer. The struct currently carries only the size field, but using a struct makes the API extensible: future callers can supply additional initialization parameters without adding more positional arguments. Update all in-tree callers (amdgpu, xe) to use a compound-literal initializer. v5: - Commit introduced. Assisted-by: GitHub_Copilot:claude-sonnet-4.6 Signed-off-by: Thomas Hellström Reviewed-by: Maarten Lankhorst Tested-by: Thadeu Lima de Souza Cascardo Link: https://patch.msgid.link/20260725100036.2372-3-thomas.hellstrom@linux.intel.com Acked-by: Dave Airlie Acked-by: Christian König Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 6 +++++- drivers/gpu/drm/drm_drv.c | 8 +++++--- drivers/gpu/drm/nouveau/nouveau_ttm.c | 5 ++++- drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 7 ++++++- include/drm/drm_drv.h | 4 +++- include/linux/cgroup_dmem.h | 16 +++++++++++++--- kernel/cgroup/dmem.c | 10 ++++++---- 7 files changed, 42 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index ac3f71d77140..08f05c3aed1d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -932,7 +933,10 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) if (err) return err; - man->cg = drmm_cgroup_register_region(adev_to_drm(adev), "vram", adev->gmc.real_vram_size); + man->cg = drmm_cgroup_register_region(adev_to_drm(adev), "vram", + &(struct dmem_cgroup_init){ + .size = adev->gmc.real_vram_size, + }); if (IS_ERR(man->cg)) return PTR_ERR(man->cg); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 1ff0bf7cba6a..3c570f9393b9 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -960,17 +960,19 @@ static void drmm_cg_unregister_region(struct drm_device *dev, void *arg) * drmm_cgroup_register_region - Register a region of a DRM device to cgroups * @dev: device for region * @region_name: Region name for registering - * @size: Size of region in bytes + * @init: Initialization parameters for the region. * * This decreases the ref-count of @dev by one. The device is destroyed if the * ref-count drops to zero. */ -struct dmem_cgroup_region *drmm_cgroup_register_region(struct drm_device *dev, const char *region_name, u64 size) +struct dmem_cgroup_region * +drmm_cgroup_register_region(struct drm_device *dev, const char *region_name, + const struct dmem_cgroup_init *init) { struct dmem_cgroup_region *region; int ret; - region = dmem_cgroup_register_region(size, "drm/%s/%s", dev->unique, region_name); + region = dmem_cgroup_register_region(init, "drm/%s/%s", dev->unique, region_name); if (IS_ERR_OR_NULL(region)) return region; diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 860bca7e3ce2..cfc0868e2dd3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -23,6 +23,7 @@ * USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include @@ -189,7 +190,9 @@ nouveau_ttm_init_vram(struct nouveau_drm *drm) man->func = &nouveau_vram_manager; man->cg = drmm_cgroup_register_region(drm->dev, "vram", - drm->gem.vram_available); + &(struct dmem_cgroup_init){ + .size = drm->gem.vram_available + }); if (IS_ERR(man->cg)) return PTR_ERR(man->cg); diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c index b518f7dec680..308fda4248eb 100644 --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c @@ -4,6 +4,8 @@ * Copyright (C) 2021-2022 Red Hat */ +#include + #include #include #include @@ -303,7 +305,10 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr, int err; name = mem_type == XE_PL_VRAM0 ? "vram0" : "vram1"; - man->cg = drmm_cgroup_register_region(&xe->drm, name, size); + man->cg = drmm_cgroup_register_region(&xe->drm, name, + &(struct dmem_cgroup_init){ + .size = size, + }); if (IS_ERR(man->cg)) return PTR_ERR(man->cg); diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index e09559495c5b..b23830494ed4 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -34,6 +34,7 @@ #include +struct dmem_cgroup_init; struct dmem_cgroup_region; struct drm_fb_helper; struct drm_fb_helper_surface_size; @@ -433,7 +434,8 @@ void *__devm_drm_dev_alloc(struct device *parent, struct dmem_cgroup_region * drmm_cgroup_register_region(struct drm_device *dev, - const char *region_name, u64 size); + const char *region_name, + const struct dmem_cgroup_init *init); /** * devm_drm_dev_alloc - Resource managed allocation of a &drm_device instance diff --git a/include/linux/cgroup_dmem.h b/include/linux/cgroup_dmem.h index 9d72457c4cb9..0575bab38d24 100644 --- a/include/linux/cgroup_dmem.h +++ b/include/linux/cgroup_dmem.h @@ -14,8 +14,18 @@ struct dmem_cgroup_pool_state; /* Opaque definition of a cgroup region, used internally */ struct dmem_cgroup_region; +/** + * struct dmem_cgroup_init - Initialization parameters for a dmem cgroup region. + * @size: Size of the region in bytes. + */ +struct dmem_cgroup_init { + u64 size; +}; + #if IS_ENABLED(CONFIG_CGROUP_DMEM) -struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *name_fmt, ...) __printf(2,3); +struct dmem_cgroup_region * +dmem_cgroup_register_region(const struct dmem_cgroup_init *init, + const char *name_fmt, ...) __printf(2, 3); void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region); int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size, struct dmem_cgroup_pool_state **ret_pool, @@ -33,8 +43,8 @@ struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgrou void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool); #else -static inline __printf(2,3) struct dmem_cgroup_region * -dmem_cgroup_register_region(u64 size, const char *name_fmt, ...) +static inline __printf(2, 3) struct dmem_cgroup_region * +dmem_cgroup_register_region(const struct dmem_cgroup_init *init, const char *name_fmt, ...) { return NULL; } diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c index 1af08b0464b8..aea21e39180a 100644 --- a/kernel/cgroup/dmem.c +++ b/kernel/cgroup/dmem.c @@ -502,7 +502,7 @@ EXPORT_SYMBOL_GPL(dmem_cgroup_unregister_region); /** * dmem_cgroup_register_region() - Register a regions for dev cgroup. - * @size: Size of region to register, in bytes. + * @init: Initialization parameters for the region. * @fmt: Region parameters to register * * This function registers a node in the dmem cgroup with the @@ -511,13 +511,15 @@ EXPORT_SYMBOL_GPL(dmem_cgroup_unregister_region); * * Return: NULL or a struct on success, PTR_ERR on failure. */ -struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *fmt, ...) +struct dmem_cgroup_region * +dmem_cgroup_register_region(const struct dmem_cgroup_init *init, + const char *fmt, ...) { struct dmem_cgroup_region *ret; char *region_name; va_list ap; - if (!size) + if (!init || !init->size) return NULL; va_start(ap, fmt); @@ -534,7 +536,7 @@ struct dmem_cgroup_region *dmem_cgroup_register_region(u64 size, const char *fmt INIT_LIST_HEAD(&ret->pools); ret->name = region_name; - ret->size = size; + ret->size = init->size; kref_init(&ret->ref); spin_lock(&dmemcg_lock); -- cgit v1.2.3 From 747c4bb450adcd8b99d3543448419e1952755832 Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Sat, 25 Jul 2026 12:00:33 +0200 Subject: cgroup/dmem: Add reclaim callback for lowering max below current usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional reclaim callback to struct dmem_cgroup_region. When dmem.max is set below the current usage of a cgroup pool, the new limit is applied immediately (so that concurrent allocations are throttled while reclaim is in progress) and then the driver is asked to evict memory to bring usage back below the limit. Reclaim is attempted up to a bounded number of times. No error is returned to userspace if usage remains above the limit after reclaim, and a pending signal will abort the reclaim loop early. This matches the behavior of memory.max in the memory cgroup controller. Also honor O_NONBLOCK so that if that flag is set during the max value write, no reclaim is initiated. The idea is to avoid charging the reclaim cost to the writer of the max value. v2: - Write max before reclaim is attempted (Maarten) - Let signals abort the reclaim without error (Maarten) - If a new max value is written with the O_NONBLOCK flag, reclaim is not attempted (Maarten) - Extract region from the pool parameter rather than passing it explicitly to set_resource_xxx(). v3: - Use an rw_semaphore (unregister_sem) to protect reclaim callbacks against concurrent region unregistration: readers (reclaim) hold the read side; dmem_cgroup_unregister_region() takes the write side to drain in-flight callbacks before returning. (Sashiko-bot) v5: - Rebased on the introduction of struct dmem_cgroup_init. - Use nonblock=true in reset_all_resource_limits() to avoid sleeping inside rcu_read_lock() in dmemcs_offline(). (Sashiko-bot) - Compare usage against the truncated limit value stored in cnt.max, not the original u64. (Sashiko-bot) - Use a DMEM_MAX_RECLAIM_RETRIES (16) retry budget instead of 5, matching the memcg controller's MAX_RECLAIM_RETRIES. Only -ENOSPC (no progress) counts against the retry budget; other errors terminate the loop immediately. v6: - Fix dmem_cgroup_ops->reclaim docstring: -ENOSPC does not stop reclaim immediately but is retried up to DMEM_MAX_RECLAIM_RETRIES times; only other negative errors terminate the loop. (Sashiko-bot) v7: - Replace the per-region rw_semaphore with a static SRCU domain (dmemcg_srcu). SRCU is a better fit than rwsem for this use: it avoids the per-region lock overhead on every reclaim call, and synchronize_srcu() at unregister time is a rare operation. (Maarten) - Trim in-function comments to focus on what rather than how. Assisted-by: GitHub_Copilot:claude-sonnet-4.6 Signed-off-by: Thomas Hellström Reviewed-by: Maarten Lankhorst Tested-by: Thadeu Lima de Souza Cascardo Link: https://patch.msgid.link/20260725100036.2372-4-thomas.hellstrom@linux.intel.com Signed-off-by: Maarten Lankhorst --- include/linux/cgroup_dmem.h | 22 +++++++++++++ kernel/cgroup/dmem.c | 80 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 90 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup_dmem.h b/include/linux/cgroup_dmem.h index 0575bab38d24..c6cad9501770 100644 --- a/include/linux/cgroup_dmem.h +++ b/include/linux/cgroup_dmem.h @@ -14,12 +14,34 @@ struct dmem_cgroup_pool_state; /* Opaque definition of a cgroup region, used internally */ struct dmem_cgroup_region; +/** + * struct dmem_cgroup_ops - Operations for a dmem cgroup region. + * @reclaim: Optional callback invoked when dmem.max is set below the current + * usage of a pool. The driver should attempt to free at least + * @target_bytes from @pool. May be called multiple times if usage + * remains above the limit after returning. + * + * Return: 0 if some progress was made (even if less than + * @target_bytes was freed), -ENOSPC if no progress could be made + * (the caller will retry up to a bounded number of times), or + * another negative error code if a fatal error occurred (stops + * further reclaim attempts immediately). + */ +struct dmem_cgroup_ops { + int (*reclaim)(struct dmem_cgroup_pool_state *pool, + u64 target_bytes, void *priv); +}; + /** * struct dmem_cgroup_init - Initialization parameters for a dmem cgroup region. * @size: Size of the region in bytes. + * @ops: Optional operations for this region. May be NULL. + * @reclaim_priv: Opaque pointer passed to @ops->reclaim. May be NULL. */ struct dmem_cgroup_init { u64 size; + const struct dmem_cgroup_ops *ops; + void *reclaim_priv; }; #if IS_ENABLED(CONFIG_CGROUP_DMEM) diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c index aea21e39180a..4683f3d68022 100644 --- a/kernel/cgroup/dmem.c +++ b/kernel/cgroup/dmem.c @@ -17,6 +17,13 @@ #include #include #include +#include + +/* Maximum reclaim attempts before giving up when lowering dmem.max. */ +#define DMEM_MAX_RECLAIM_RETRIES 16 + +/* SRCU domain serialising reclaim callbacks against region unregistration. */ +DEFINE_STATIC_SRCU(dmemcg_srcu); struct dmem_cgroup_region { /** @@ -48,9 +55,18 @@ struct dmem_cgroup_region { /** * @unregistered: Whether the region is unregistered by its caller. - * No new pools should be added to the region afterwards. + * No new pools should be added to the region afterwards, and no new + * reclaim callbacks should be invoked. */ bool unregistered; + + /** + * @ops: Optional driver operations for this region. + */ + const struct dmem_cgroup_ops *ops; + + /** @reclaim_priv: Private data passed to @ops->reclaim. */ + void *reclaim_priv; }; struct dmemcg_state { @@ -145,21 +161,52 @@ static void free_cg_pool(struct dmem_cgroup_pool_state *pool) } static void -set_resource_min(struct dmem_cgroup_pool_state *pool, u64 val) +set_resource_min(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock) { page_counter_set_min(&pool->cnt, val); } static void -set_resource_low(struct dmem_cgroup_pool_state *pool, u64 val) +set_resource_low(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock) { page_counter_set_low(&pool->cnt, val); } static void -set_resource_max(struct dmem_cgroup_pool_state *pool, u64 val) +set_resource_max(struct dmem_cgroup_pool_state *pool, u64 val, bool nonblock) { - page_counter_set_max(&pool->cnt, val); + struct dmem_cgroup_region *region = pool->region; + unsigned long limit = (unsigned long)val; + + /* Apply the new limit immediately so concurrent allocations are throttled. */ + xchg(&pool->cnt.max, limit); + + if (nonblock) + return; + + int srcu_idx = srcu_read_lock(&dmemcg_srcu); + + if (!READ_ONCE(region->unregistered) && region->ops && region->ops->reclaim) { + for (int retries = DMEM_MAX_RECLAIM_RETRIES; ; ) { + u64 usage = page_counter_read(&pool->cnt); + int ret; + + if (usage <= limit) + break; + + if (signal_pending(current)) + break; + + ret = region->ops->reclaim(pool, usage - limit, region->reclaim_priv); + + /* -ENOSPC means no progress; other errors are fatal. */ + if (ret && (ret != -ENOSPC || !retries--)) + break; + + cond_resched(); + } + } + srcu_read_unlock(&dmemcg_srcu, srcu_idx); } static u64 get_resource_low(struct dmem_cgroup_pool_state *pool) @@ -189,9 +236,10 @@ static u64 get_resource_peak(struct dmem_cgroup_pool_state *pool) static void reset_all_resource_limits(struct dmem_cgroup_pool_state *rpool) { - set_resource_min(rpool, 0); - set_resource_low(rpool, 0); - set_resource_max(rpool, PAGE_COUNTER_MAX); + set_resource_min(rpool, 0, false); + set_resource_low(rpool, 0, false); + /* nonblock: raising to max makes reclaim a no-op; sleeping is forbidden here. */ + set_resource_max(rpool, PAGE_COUNTER_MAX, true); } static void dmemcs_offline(struct cgroup_subsys_state *css) @@ -468,7 +516,10 @@ static void dmemcg_free_region(struct kref *ref) * dmem_cgroup_unregister_region() - Unregister a previously registered region. * @region: The region to unregister. * - * This function undoes dmem_cgroup_register_region. + * This function undoes dmem_cgroup_register_region. It drains any + * in-flight reclaim callbacks before returning, so the caller may safely + * free the resources pointed to by the @reclaim_priv that was passed at + * registration time. */ void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region) { @@ -493,9 +544,11 @@ void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region) * no new pools should be added to the dead region * by get_cg_pool_unlocked. */ - region->unregistered = true; + WRITE_ONCE(region->unregistered, true); spin_unlock(&dmemcg_lock); + synchronize_srcu(&dmemcg_srcu); + kref_put(®ion->ref, dmemcg_free_region); } EXPORT_SYMBOL_GPL(dmem_cgroup_unregister_region); @@ -537,6 +590,8 @@ dmem_cgroup_register_region(const struct dmem_cgroup_init *init, INIT_LIST_HEAD(&ret->pools); ret->name = region_name; ret->size = init->size; + ret->ops = init->ops; + ret->reclaim_priv = init->reclaim_priv; kref_init(&ret->ref); spin_lock(&dmemcg_lock); @@ -837,11 +892,12 @@ static int dmemcg_parse_limit(char *options, u64 *new_limit) static ssize_t dmemcg_limit_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off, - void (*apply)(struct dmem_cgroup_pool_state *, u64)) + void (*apply)(struct dmem_cgroup_pool_state *, u64, bool)) { struct dmemcg_state *dmemcs = css_to_dmemcs(of_css(of)); struct dmem_cgroup_pool_state *pool; struct dmem_cgroup_region *region; + bool nonblock = of->file->f_flags & O_NONBLOCK; char *region_name; u64 new_limit; int err; @@ -867,7 +923,7 @@ static ssize_t dmemcg_limit_write(struct kernfs_open_file *of, goto out_put; } - apply(pool, new_limit); + apply(pool, new_limit, nonblock); dmemcg_pool_put(pool); out_put: -- cgit v1.2.3