* [PATCH v8 0/6] Add reclaim to the dmem cgroup controller
@ 2026-07-23 10:03 Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 1/6] drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init() Thomas Hellström
` (8 more replies)
0 siblings, 9 replies; 16+ messages in thread
From: Thomas Hellström @ 2026-07-23 10:03 UTC (permalink / raw)
To: intel-xe
Cc: Thomas Hellström, Natalie Vock, Johannes Weiner, Tejun Heo,
Michal Koutný, cgroups, Huang Rui, Matthew Brost,
Matthew Auld, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Simona Vetter, David Airlie, Christian König,
Thadeu Lima de Souza Cascardo, Alex Deucher, Rodrigo Vivi,
dri-devel, amd-gfx, linux-kernel
When writing a "max" limit lower than the current usage, the
existing code silently failed. This series aims to improve
on that by returning -EBUSY on failure and also attempt
to synchronously reclaim device memory to push the usage
under the new max limit to avoid the error.
Patch 1 fixes a pre-existing amdgpu_vram_mgr_init() error path
Patch 2 introduces struct dmem_cgroup_init for extensible region
registration.
Patch 3 implements and documents a reclaim callback interface
for the dmem controller.
Patch 4 implements a TTM reclaim callback.
Patches 5-6 hook up the reclaim callback to the dmem cgroup-aware
drivers xe and amdgpu.
v2:
- Remove the error propagation that was in a previous series (Maarten)
- A number of updates in patch 1. See its commit message for
details (Maarten)
v3:
- Add patch 1 fixing a pre-existing amdgpu_vram_mgr_init() error path
bug where drmm_cgroup_register_region() was called before
INIT_LIST_HEAD() and gpu_buddy_init(), causing a kernel panic on
failure. (Sashiko-bot)
- Use an rwsem to protect reclaim callback registration and region
unregister against concurrent reclaim invocations. (Sashiko-bot)
- Fix ttm_resource_manager_set_dmem_region() storing an error pointer
in man->cg unconditionally. (Sashiko-bot)
- Fix kernel-doc function name format for ttm_bo_evict_cgroup() and
ttm_resource_manager_set_dmem_region().
v4:
- Rebased on drm-tip; dropped the XE_PL_STOLEN guard in the xe patch
as stolen memory uses a separate TTM manager.
v5:
- Add patch 2 introducing struct dmem_cgroup_init to make the
dmem_cgroup_register_region() API extensible without adding positional
arguments in the future.
- 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 stored in cnt.max, not the
original u64. (Sashiko-bot)
- Use DMEM_MAX_RECLAIM_RETRIES (16) retry budget instead of 5, matching
the memcg controller; only -ENOSPC (no progress) counts against the
budget, other errors abort immediately.
- Handle NULL region in ttm_resource_manager_set_dmem_region() to clear
the reclaim callback, preventing use-after-free when the manager is
torn down while the dmem region outlives it. (Sashiko-bot)
- Return 0 on any eviction progress; reserve -ENOSPC for zero progress.
- Clear the reclaim callback in xe and amdgpu fini paths to prevent
use-after-free after driver unbind with open DRM file descriptors.
(Sashiko-bot)
- Register xe fini devres action before drmm_cgroup_register_region()
so LIFO teardown runs unregister first, draining callbacks before the
manager is destroyed. (Sashiko-bot)
- Switch amdgpu to explicit dmem_cgroup_unregister_region() at the top
of amdgpu_vram_mgr_fini() before any manager teardown, since amdgpu's
fini is called explicitly during driver unbind before drmm cleanup.
(Sashiko-bot)
- Wrap the xe reclaim callback with drm_dev_enter()/drm_dev_exit() to
prevent TTM reclaim from running after driver unbind.
v6:
- Move the ops check inside down_read() in set_resource_max(), guarded
by region->unregistered, to close a UAF race against
dmem_cgroup_unregister_region(). (Sashiko-bot)
- Fix dmem_cgroup_ops->reclaim docstring: -ENOSPC is retried up to
DMEM_MAX_RECLAIM_RETRIES times, not an immediate stop. (Sashiko-bot)
- Fix mgr->cg_region never being assigned in amdgpu_vram_mgr_init(),
causing dmem_cgroup_unregister_region() in fini to silently no-op.
(Sashiko-bot)
- Reorder amdgpu_vram_mgr_fini() to call set_used(false) and
evict_all() before dmem_cgroup_unregister_region(), so
ttm_resource_free() can uncharge via man->cg during eviction; clear
man->cg after unregister. (Sashiko-bot)
v7:
- Replace the per-region rw_semaphore with a static SRCU domain
(dmemcg_srcu). SRCU is a better fit: it avoids per-region lock
overhead on every reclaim call, and synchronize_srcu() at unregister
time is a rare, shutdown-time operation. (Maarten)
- Trim in-function comments to focus on what rather than how.
- Switch back to drmm_cgroup_register_region() with a drm_dev_enter/
exit guard in the reclaim callback (matching xe), rather than manual
register/unregister. drm_dev_unplug() fires before vram_mgr_fini(),
so drm_dev_enter() returning false prevents any reclaim from touching
the manager during teardown. This also fixes the "vram" name
collision on multi-GPU systems, since drmm_cgroup_register_region()
automatically prefixes with "drm/<pci-addr>/". (Sashiko-bot)
v8:
- Fix ttm_resource_manager_set_dmem_region() using IS_ERR_OR_NULL(),
which skipped the assignment for a NULL region and thus never cleared
man->cg. Use IS_ERR() so that a NULL region detaches the region as the
kernel-doc and the v5 changelog intended. (Sashiko-bot)
- Move the amdgpu dmem cgroup region teardown back into
amdgpu_vram_mgr_fini() with an explicit dmem_cgroup_unregister_region()
after evict_all(), keeping the drm_dev_enter() guard. The v7 drmm-only
approach left a use-after-free on the probe-error teardown path, where
drm_dev_unplug() is never called so the drm_dev_enter() guard stays
open while drm_driver.release destroys the manager before the drmm
action unregisters the region. (Sashiko-bot)
User-space tests are at
https://patchwork.freedesktop.org/series/163935/
Test-with: 20260428065411.4222-1-thomas.hellstrom@linux.intel.com
Thomas Hellström (6):
drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init()
cgroup/dmem: Introduce struct dmem_cgroup_init for region
initialization
cgroup/dmem: Add reclaim callback for lowering max below current usage
drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem
controller
drm/xe: Wire up dmem cgroup reclaim for VRAM manager
drm/amdgpu: Wire up dmem cgroup reclaim for VRAM manager
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 52 ++++++++++-
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 3 +
drivers/gpu/drm/drm_drv.c | 8 +-
drivers/gpu/drm/ttm/ttm_bo.c | 95 +++++++++++++++++++-
drivers/gpu/drm/ttm/ttm_bo_util.c | 3 +-
drivers/gpu/drm/ttm/ttm_resource.c | 52 +++++++++++
drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 53 +++++++++--
include/drm/drm_drv.h | 4 +-
include/drm/ttm/ttm_bo.h | 10 +++
include/drm/ttm/ttm_resource.h | 7 ++
include/linux/cgroup_dmem.h | 38 +++++++-
kernel/cgroup/dmem.c | 90 +++++++++++++++----
13 files changed, 380 insertions(+), 37 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v8 1/6] drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init()
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
@ 2026-07-23 10:03 ` Thomas Hellström
2026-07-23 10:23 ` sashiko-bot
2026-07-23 10:03 ` [PATCH v8 2/6] cgroup/dmem: Introduce struct dmem_cgroup_init for region initialization Thomas Hellström
` (7 subsequent siblings)
8 siblings, 1 reply; 16+ messages in thread
From: Thomas Hellström @ 2026-07-23 10:03 UTC (permalink / raw)
To: intel-xe
Cc: Thomas Hellström, Sashiko-bot, Friedrich Vock,
Maarten Lankhorst, Tejun Heo, Maxime Ripard, Christian König,
Alex Deucher, amd-gfx, dri-devel, stable,
Arunpravin Paneer Selvam, Natalie Vock, Johannes Weiner,
Michal Koutný, cgroups, Huang Rui, Matthew Brost,
Matthew Auld, Maarten Lankhorst, Thomas Zimmermann, Simona Vetter,
David Airlie, Thadeu Lima de Souza Cascardo, Rodrigo Vivi,
linux-kernel
drmm_cgroup_register_region() is called before INIT_LIST_HEAD() and
gpu_buddy_init() in amdgpu_vram_mgr_init(). If it fails, the function
returns early and bypasses those initializations.
Since adev->mman.initialized is set to true before amdgpu_vram_mgr_init()
is called, a failure triggers amdgpu_ttm_fini(), which calls
amdgpu_vram_mgr_fini(), which then:
- Calls list_for_each_entry_safe() on reservations_pending and
reserved_pages, whose list_head::next pointers are zero-initialized
(NULL). The loop does not recognize them as empty and dereferences NULL.
- Calls gpu_buddy_fini(), which iterates free_trees[] unconditionally
via for_each_free_tree(). Since mm->free_trees is NULL
(never allocated), this dereferences NULL.
Both result in a kernel panic on the module load error path.
Fix by moving drmm_cgroup_register_region() to after the list and buddy
allocator are fully initialized, so the teardown path is safe to run.
Reported-by: Sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260428073116.15687-1-thomas.hellstrom@linux.intel.com?part=4
Fixes: 2b624a2c1865 ("drm/ttm: Handle cgroup based eviction in TTM")
Cc: Friedrich Vock <friedrich.vock@gmx.de>
Cc: Maarten Lankhorst <dev@lankhorst.se>
Cc: Tejun Heo <tj@kernel.org>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Christian König <christian.koenig@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: amd-gfx@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org
Cc: <stable@vger.kernel.org> # v6.14+
Assisted-by: GitHub_Copilot:claude-sonnet-4.6
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 2a241a5b12c4..ac3f71d77140 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -918,9 +918,6 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
struct ttm_resource_manager *man = &mgr->manager;
int err;
- man->cg = drmm_cgroup_register_region(adev_to_drm(adev), "vram", adev->gmc.real_vram_size);
- if (IS_ERR(man->cg))
- return PTR_ERR(man->cg);
ttm_resource_manager_init(man, &adev->mman.bdev,
adev->gmc.real_vram_size);
@@ -935,6 +932,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);
+ if (IS_ERR(man->cg))
+ return PTR_ERR(man->cg);
+
ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
ttm_resource_manager_set_used(man, true);
return 0;
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v8 2/6] cgroup/dmem: Introduce struct dmem_cgroup_init for region initialization
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 1/6] drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init() Thomas Hellström
@ 2026-07-23 10:03 ` Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 3/6] cgroup/dmem: Add reclaim callback for lowering max below current usage Thomas Hellström
` (6 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Thomas Hellström @ 2026-07-23 10:03 UTC (permalink / raw)
To: intel-xe
Cc: Thomas Hellström, Maarten Lankhorst, Natalie Vock,
Johannes Weiner, Tejun Heo, Michal Koutný, cgroups,
Huang Rui, Matthew Brost, Matthew Auld, Maxime Ripard,
Thomas Zimmermann, Simona Vetter, David Airlie,
Christian König, Thadeu Lima de Souza Cascardo, Alex Deucher,
Rodrigo Vivi, dri-devel, amd-gfx, linux-kernel
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 <thomas.hellstrom@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 6 +++++-
drivers/gpu/drm/drm_drv.c | 8 +++++---
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 ++++++----
6 files changed, 38 insertions(+), 13 deletions(-)
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 <linux/dma-mapping.h>
+#include <linux/cgroup_dmem.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/drm_drv.h>
#include <drm/drm_buddy.h>
@@ -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 e51ed959da89..c808958a2188 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -968,17 +968,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/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 <linux/cgroup_dmem.h>
+
#include <drm/drm_managed.h>
#include <drm/drm_drv.h>
#include <drm/drm_buddy.h>
@@ -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 <drm/drm_device.h>
+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 dd4869f1d736..d9eab8a2c1ee 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,
@@ -27,8 +37,8 @@ bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool,
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 39930c59cb76..eb46e99b7366 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);
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v8 3/6] cgroup/dmem: Add reclaim callback for lowering max below current usage
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 1/6] drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init() Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 2/6] cgroup/dmem: Introduce struct dmem_cgroup_init for region initialization Thomas Hellström
@ 2026-07-23 10:03 ` Thomas Hellström
2026-07-23 10:21 ` sashiko-bot
2026-07-23 10:03 ` [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller Thomas Hellström
` (5 subsequent siblings)
8 siblings, 1 reply; 16+ messages in thread
From: Thomas Hellström @ 2026-07-23 10:03 UTC (permalink / raw)
To: intel-xe
Cc: Thomas Hellström, Maarten Lankhorst, Natalie Vock,
Johannes Weiner, Tejun Heo, Michal Koutný, cgroups,
Huang Rui, Matthew Brost, Matthew Auld, Maxime Ripard,
Thomas Zimmermann, Simona Vetter, David Airlie,
Christian König, Thadeu Lima de Souza Cascardo, Alex Deucher,
Rodrigo Vivi, dri-devel, amd-gfx, linux-kernel
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 <thomas.hellstrom@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
include/linux/cgroup_dmem.h | 22 ++++++++++
kernel/cgroup/dmem.c | 80 +++++++++++++++++++++++++++++++------
2 files changed, 90 insertions(+), 12 deletions(-)
diff --git a/include/linux/cgroup_dmem.h b/include/linux/cgroup_dmem.h
index d9eab8a2c1ee..8664321fa9f7 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 eb46e99b7366..7e427895f23e 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -17,6 +17,13 @@
#include <linux/refcount.h>
#include <linux/rculist.h>
#include <linux/slab.h>
+#include <linux/srcu.h>
+
+/* 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);
@@ -733,11 +788,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;
@@ -763,7 +819,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:
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
` (2 preceding siblings ...)
2026-07-23 10:03 ` [PATCH v8 3/6] cgroup/dmem: Add reclaim callback for lowering max below current usage Thomas Hellström
@ 2026-07-23 10:03 ` Thomas Hellström
2026-07-23 10:31 ` sashiko-bot
2026-07-23 12:02 ` Maarten Lankhorst
2026-07-23 10:03 ` [PATCH v8 5/6] drm/xe: Wire up dmem cgroup reclaim for VRAM manager Thomas Hellström
` (4 subsequent siblings)
8 siblings, 2 replies; 16+ messages in thread
From: Thomas Hellström @ 2026-07-23 10:03 UTC (permalink / raw)
To: intel-xe
Cc: Thomas Hellström, Maarten Lankhorst, Natalie Vock,
Johannes Weiner, Tejun Heo, Michal Koutný, cgroups,
Huang Rui, Matthew Brost, Matthew Auld, Maxime Ripard,
Thomas Zimmermann, Simona Vetter, David Airlie,
Christian König, Thadeu Lima de Souza Cascardo, Alex Deucher,
Rodrigo Vivi, dri-devel, amd-gfx, linux-kernel
Add ttm_bo_evict_cgroup() to evict buffer objects charged to a specific
dmem cgroup pool from a resource manager's LRU until a byte target is
met. Add ttm_resource_manager_set_dmem_region() to associate a dmem
cgroup region with a resource manager; drivers supply their own
dmem_cgroup_ops with ttm_resource_manager_dmem_reclaim as the reclaim
function and the manager pointer as reclaim_priv in the dmem_cgroup_init
to wire up TTM eviction as the reclaim callback.
The eviction context is interruptible; signals abort the operation and
propagate back through the write() syscall.
Introduce a new mode for the bo LRU walker so that sleeping locks
can be taken. This can be used when the caller doesn't hold any
previous dma_resv locks, and where it intends to hold at most
one lock at a time.
Like the rest of the TTM eviction this should sooner than later
be converted to full WW transactions.
v3:
- Fix ttm_resource_manager_set_dmem_region() storing an error pointer
in man->cg unconditionally. (Sashiko-bot)
- Fix kernel-doc function name format for ttm_bo_evict_cgroup() and
ttm_resource_manager_set_dmem_region().
v5:
- Rebased on the introduction of struct dmem_cgroup_init.
- Handle NULL region in ttm_resource_manager_set_dmem_region() to clear
the reclaim callback, preventing use-after-free when the manager is
torn down while the dmem region outlives it. (Sashiko-bot)
- Return 0 on any progress (even partial eviction), -ENOSPC only when
nothing was freed; fixes callers that expected 0 on partial success.
- Document that the reclaim callback should return 0 if some progress
was made, -ENOSPC if no progress at all, or another error for fatal
failures.
v8:
- Fix ttm_resource_manager_set_dmem_region() using IS_ERR_OR_NULL(),
which skipped the assignment for a NULL region and thus never
cleared man->cg. Use IS_ERR() so that a NULL region detaches the
region as the kernel-doc and the v5 changelog intended. (Sashiko-bot)
Assisted-by: GitHub_Copilot:claude-sonnet-4.6
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> #v7
---
drivers/gpu/drm/ttm/ttm_bo.c | 95 +++++++++++++++++++++++++++++-
drivers/gpu/drm/ttm/ttm_bo_util.c | 3 +-
drivers/gpu/drm/ttm/ttm_resource.c | 52 ++++++++++++++++
include/drm/ttm/ttm_bo.h | 10 ++++
include/drm/ttm/ttm_resource.h | 7 +++
5 files changed, 163 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 3980f376e3ba..b2bbbb69add3 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -515,12 +515,20 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
{
struct ttm_bo_evict_walk *evict_walk =
container_of(walk, typeof(*evict_walk), walk);
+ /* Capture size before eviction in case res is cleared. */
+ s64 bo_size = bo->base.size;
s64 lret;
if (!dmem_cgroup_state_evict_valuable(evict_walk->limit_pool, bo->resource->css,
evict_walk->try_low, &evict_walk->hit_low))
return 0;
+ /*
+ * evict_walk->place is NULL in cgroup drain mode. Drivers'
+ * eviction_valuable() callbacks must handle a NULL place, treating it
+ * as "any placement": the TTM base implementation already does so via
+ * ttm_resource_intersects().
+ */
if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place))
return 0;
@@ -536,11 +544,15 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
goto out;
evict_walk->evicted++;
- if (evict_walk->res)
+ if (evict_walk->res) {
lret = ttm_resource_alloc(evict_walk->evictor, evict_walk->place,
evict_walk->res, NULL);
- if (lret == 0)
- return 1;
+ if (lret == 0)
+ return 1;
+ } else {
+ /* Cgroup drain: return bytes freed for byte-denominated progress. */
+ return bo_size;
+ }
out:
/* Errors that should terminate the walk. */
if (lret == -ENOSPC)
@@ -614,6 +626,83 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
return 0;
}
+/**
+ * ttm_bo_evict_cgroup() - Evict buffer objects charged to a specific cgroup.
+ * @bdev: The TTM device.
+ * @man: The resource manager whose LRU to walk.
+ * @limit_pool: The cgroup pool state whose members should be evicted.
+ * @target_bytes: Number of bytes to free.
+ * @ctx: The TTM operation context.
+ *
+ * Walk the LRU of @man and evict buffer objects that are charged to the
+ * cgroup identified by @limit_pool, until at least @target_bytes have been
+ * freed. Mirrors the two-pass (trylock -> sleeping-lock, low-watermark)
+ * strategy used by ttm_bo_evict_alloc().
+ *
+ * Return: >= @target_bytes on full success, 0..target_bytes-1 if partial,
+ * negative error code on fatal error.
+ */
+s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
+ struct ttm_resource_manager *man,
+ struct dmem_cgroup_pool_state *limit_pool,
+ s64 target_bytes,
+ struct ttm_operation_ctx *ctx)
+{
+ struct ttm_bo_evict_walk evict_walk = {
+ .walk = {
+ .ops = &ttm_evict_walk_ops,
+ .arg = { .ctx = ctx },
+ },
+ .limit_pool = limit_pool,
+ /* place, evictor, res left NULL: selects cgroup drain mode */
+ };
+ s64 lret, pass;
+
+ evict_walk.walk.arg.trylock_only = true;
+ lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, target_bytes);
+ if (lret < 0 || lret >= target_bytes)
+ return lret;
+
+ /* Second pass: also evict BOs at the low watermark. */
+ if (evict_walk.hit_low) {
+ evict_walk.try_low = true;
+ pass = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
+ target_bytes - lret);
+ if (pass < 0)
+ return pass;
+ lret += pass;
+ if (lret >= target_bytes)
+ return lret;
+ }
+
+ /* Full sleeping-lock pass for remaining target. */
+ evict_walk.try_low = evict_walk.hit_low = false;
+ evict_walk.walk.arg.trylock_only = false;
+
+retry:
+ evict_walk.walk.arg.sleeping_lock = true;
+ do {
+ evict_walk.evicted = 0;
+ pass = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
+ target_bytes - lret);
+ if (pass < 0) {
+ lret = pass;
+ goto out;
+ }
+ lret += pass;
+ } while (lret < target_bytes && evict_walk.evicted);
+
+ /* One more attempt if we hit the low limit during sleeping-lock pass. */
+ if (lret < target_bytes && evict_walk.hit_low && !evict_walk.try_low) {
+ evict_walk.try_low = true;
+ goto retry;
+ }
+
+out:
+ return lret;
+}
+EXPORT_SYMBOL(ttm_bo_evict_cgroup);
+
/**
* ttm_bo_pin - Pin the buffer object.
* @bo: The buffer object to pin
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 3e3c201a0222..bd0b23ac2cc4 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -999,7 +999,8 @@ __ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
bo = res->bo;
if (ttm_lru_walk_trylock(curs, bo))
bo_locked = true;
- else if (!arg->ticket || arg->ctx->no_wait_gpu || arg->trylock_only)
+ else if ((!arg->ticket && !arg->sleeping_lock) || arg->ctx->no_wait_gpu ||
+ arg->trylock_only)
continue;
if (!ttm_bo_get_unless_zero(bo)) {
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
index 154d6739256f..1ff4a470b083 100644
--- a/drivers/gpu/drm/ttm/ttm_resource.c
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -953,3 +953,55 @@ void ttm_resource_manager_create_debugfs(struct ttm_resource_manager *man,
#endif
}
EXPORT_SYMBOL(ttm_resource_manager_create_debugfs);
+
+/**
+ * ttm_resource_manager_dmem_reclaim() - dmem cgroup reclaim callback for TTM
+ * resource managers.
+ * @pool: The dmem cgroup pool state for the cgroup being reclaimed.
+ * @target_bytes: Number of bytes to try to free.
+ * @priv: The &ttm_resource_manager pointer, passed as @init.reclaim_priv to
+ * dmem_cgroup_register_region().
+ *
+ * Drivers should use this as the @reclaim member of their own
+ * &struct dmem_cgroup_ops, with the &ttm_resource_manager pointer as
+ * @init.reclaim_priv.
+ *
+ * Return: 0 if some memory was freed, -ENOSPC if nothing was freed, or
+ * another negative error code on fatal failure.
+ */
+int ttm_resource_manager_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
+ u64 target_bytes, void *priv)
+{
+ struct ttm_resource_manager *man = priv;
+ struct ttm_operation_ctx ctx = { .interruptible = true };
+ s64 freed;
+
+ freed = ttm_bo_evict_cgroup(man->bdev, man, pool, target_bytes, &ctx);
+ if (freed < 0)
+ return freed;
+
+ return freed > 0 ? 0 : -ENOSPC;
+}
+EXPORT_SYMBOL(ttm_resource_manager_dmem_reclaim);
+
+/**
+ * ttm_resource_manager_set_dmem_region() - Associate a dmem cgroup region with a
+ * resource manager.
+ * @man: The resource manager.
+ * @region: The dmem cgroup region to associate, may be NULL or IS_ERR().
+ *
+ * When @region is valid, stores it in @man->cg so that TTM can look up the
+ * associated pool during charging and eviction-target selection. When
+ * @region is %NULL, clears @man->cg to detach the region before teardown.
+ * An IS_ERR() @region is ignored, leaving @man->cg unchanged.
+ * The reclaim callback must be wired up using ttm_resource_manager_dmem_reclaim()
+ * in the driver's own &struct dmem_cgroup_ops, with the manager pointer as
+ * @init.reclaim_priv.
+ */
+void ttm_resource_manager_set_dmem_region(struct ttm_resource_manager *man,
+ struct dmem_cgroup_region *region)
+{
+ if (!IS_ERR(region))
+ man->cg = region;
+}
+EXPORT_SYMBOL(ttm_resource_manager_set_dmem_region);
diff --git a/include/drm/ttm/ttm_bo.h b/include/drm/ttm/ttm_bo.h
index 8310bc3d55f9..32791c4db2a9 100644
--- a/include/drm/ttm/ttm_bo.h
+++ b/include/drm/ttm/ttm_bo.h
@@ -226,6 +226,11 @@ struct ttm_lru_walk_arg {
struct ww_acquire_ctx *ticket;
/** @trylock_only: Only use trylock for locking. */
bool trylock_only;
+ /**
+ * @sleeping_lock: Use sleeping locks even with %NULL @ticket.
+ * @trylock_only has precedence over this field.
+ */
+ bool sleeping_lock;
};
/**
@@ -431,6 +436,11 @@ void ttm_bo_unpin(struct ttm_buffer_object *bo);
int ttm_bo_evict_first(struct ttm_device *bdev,
struct ttm_resource_manager *man,
struct ttm_operation_ctx *ctx);
+s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
+ struct ttm_resource_manager *man,
+ struct dmem_cgroup_pool_state *limit_pool,
+ s64 target_bytes,
+ struct ttm_operation_ctx *ctx);
int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset,
void *buf, int len, int write);
vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h
index a5d386583fb6..32e485fdce9a 100644
--- a/include/drm/ttm/ttm_resource.h
+++ b/include/drm/ttm/ttm_resource.h
@@ -39,6 +39,7 @@
struct dentry;
struct dmem_cgroup_device;
+struct dmem_cgroup_region;
struct drm_printer;
struct ttm_device;
struct ttm_resource_manager;
@@ -477,6 +478,12 @@ void ttm_resource_manager_init(struct ttm_resource_manager *man,
struct ttm_device *bdev,
uint64_t size);
+void ttm_resource_manager_set_dmem_region(struct ttm_resource_manager *man,
+ struct dmem_cgroup_region *region);
+
+int ttm_resource_manager_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
+ u64 target_bytes, void *priv);
+
int ttm_resource_manager_evict_all(struct ttm_device *bdev,
struct ttm_resource_manager *man);
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v8 5/6] drm/xe: Wire up dmem cgroup reclaim for VRAM manager
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
` (3 preceding siblings ...)
2026-07-23 10:03 ` [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller Thomas Hellström
@ 2026-07-23 10:03 ` Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 6/6] drm/amdgpu: " Thomas Hellström
` (3 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Thomas Hellström @ 2026-07-23 10:03 UTC (permalink / raw)
To: intel-xe
Cc: Thomas Hellström, Maarten Lankhorst, Natalie Vock,
Johannes Weiner, Tejun Heo, Michal Koutný, cgroups,
Huang Rui, Matthew Brost, Matthew Auld, Maxime Ripard,
Thomas Zimmermann, Simona Vetter, David Airlie,
Christian König, Thadeu Lima de Souza Cascardo, Alex Deucher,
Rodrigo Vivi, dri-devel, amd-gfx, linux-kernel
Register the VRAM manager with the dmem cgroup reclaim infrastructure
so that lowering dmem.max below current VRAM usage triggers TTM
eviction rather than failing with -EBUSY.
v4:
- Rebased on drm-tip; dropped the XE_PL_STOLEN guard as stolen memory
uses a separate TTM manager and never calls __xe_ttm_vram_mgr_init().
v5:
- Rebased on the introduction of struct dmem_cgroup_init.
- Register the fini drmm action before drmm_cgroup_register_region() so
that devres LIFO teardown runs unregister_region() first (draining any
in-flight reclaim callbacks via the rwsem) and xe_ttm_vram_mgr_fini()
second, ensuring the manager is never accessed by a reclaim callback
after teardown. (Sashiko-bot)
- Wrap the reclaim callback in xe_ttm_vram_mgr_dmem_reclaim() using
drm_dev_enter()/drm_dev_exit() to prevent TTM reclaim from running
after driver unbind.
Assisted-by: GitHub_Copilot:claude-sonnet-4.6
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 54 +++++++++++++++++++++++-----
1 file changed, 45 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
index 308fda4248eb..b2500344cd57 100644
--- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
+++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
@@ -276,6 +276,28 @@ static const struct ttm_resource_manager_func xe_ttm_vram_mgr_func = {
.debug = xe_ttm_vram_mgr_debug
};
+static const struct dmem_cgroup_ops xe_ttm_vram_mgr_dmem_ops;
+
+static int xe_ttm_vram_mgr_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
+ u64 target_bytes, void *priv)
+{
+ struct ttm_resource_manager *man = priv;
+ struct xe_device *xe = ttm_to_xe_device(man->bdev);
+ int ret, idx;
+
+ if (!drm_dev_enter(&xe->drm, &idx))
+ return -ENODEV;
+
+ ret = ttm_resource_manager_dmem_reclaim(pool, target_bytes, priv);
+
+ drm_dev_exit(idx);
+ return ret;
+}
+
+static const struct dmem_cgroup_ops xe_ttm_vram_mgr_dmem_ops = {
+ .reclaim = xe_ttm_vram_mgr_dmem_reclaim,
+};
+
static void xe_ttm_vram_mgr_fini(struct drm_device *dev, void *arg)
{
struct xe_device *xe = to_xe_device(dev);
@@ -301,17 +323,10 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr,
u64 default_page_size)
{
struct ttm_resource_manager *man = &mgr->manager;
+ struct dmem_cgroup_region *cg;
const char *name;
int err;
- name = mem_type == XE_PL_VRAM0 ? "vram0" : "vram1";
- 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);
-
man->func = &xe_ttm_vram_mgr_func;
mgr->mem_type = mem_type;
err = drmm_mutex_init(&xe->drm, &mgr->lock);
@@ -330,7 +345,28 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr,
ttm_set_driver_manager(&xe->ttm, mem_type, &mgr->manager);
ttm_resource_manager_set_used(&mgr->manager, true);
- return drmm_add_action_or_reset(&xe->drm, xe_ttm_vram_mgr_fini, mgr);
+ /*
+ * Register the fini action before the cgroup region so that devres
+ * LIFO teardown runs unregister_region first (draining any in-flight
+ * reclaim callbacks) and the manager fini second.
+ */
+ err = drmm_add_action_or_reset(&xe->drm, xe_ttm_vram_mgr_fini, mgr);
+ if (err)
+ return err;
+
+ name = mem_type == XE_PL_VRAM0 ? "vram0" : "vram1";
+ cg = drmm_cgroup_register_region(&xe->drm, name,
+ &(struct dmem_cgroup_init){
+ .size = size,
+ .ops = &xe_ttm_vram_mgr_dmem_ops,
+ .reclaim_priv = man,
+ });
+ if (IS_ERR(cg))
+ return PTR_ERR(cg);
+
+ ttm_resource_manager_set_dmem_region(man, cg);
+
+ return 0;
}
/**
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v8 6/6] drm/amdgpu: Wire up dmem cgroup reclaim for VRAM manager
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
` (4 preceding siblings ...)
2026-07-23 10:03 ` [PATCH v8 5/6] drm/xe: Wire up dmem cgroup reclaim for VRAM manager Thomas Hellström
@ 2026-07-23 10:03 ` Thomas Hellström
2026-07-23 10:50 ` sashiko-bot
2026-07-23 11:47 ` ✗ CI.checkpatch: warning for Add reclaim to the dmem cgroup controller (rev8) Patchwork
` (2 subsequent siblings)
8 siblings, 1 reply; 16+ messages in thread
From: Thomas Hellström @ 2026-07-23 10:03 UTC (permalink / raw)
To: intel-xe
Cc: Thomas Hellström, Natalie Vock, Johannes Weiner, Tejun Heo,
Michal Koutný, cgroups, Huang Rui, Matthew Brost,
Matthew Auld, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Simona Vetter, David Airlie, Christian König,
Thadeu Lima de Souza Cascardo, Alex Deucher, Rodrigo Vivi,
dri-devel, amd-gfx, linux-kernel
Register the VRAM manager with the dmem cgroup reclaim infrastructure
so that lowering dmem.max below current VRAM usage triggers TTM
eviction rather than failing with -EBUSY.
Guard place->flags in amdgpu_ttm_bo_eviction_valuable() against NULL,
as the TTM reclaim path passes a NULL place in cgroup drain mode.
Use drmm_cgroup_register_region() so that the region is automatically
unregistered at DRM device release, after drm_dev_unplug() has already
made drm_dev_enter() return false. The drm_dev_enter/exit guard in the
reclaim callback ensures no reclaim work touches the TTM manager after
driver unbind, closing the window between vram_mgr_fini() (called from
drm_driver.release) and the drmm cleanup that unregisters the region.
v3:
- Rebased on fix for uninitialized list and buddy allocator on the
drmm_cgroup_register_region() error path.
v5:
- Rebased on the introduction of struct dmem_cgroup_init.
- Clear the reclaim callback in amdgpu_vram_mgr_fini() to prevent
use-after-free if cgroup reclaim is triggered after driver unbind
while userspace holds an open DRM file descriptor. (Sashiko-bot)
- Switch from drmm_cgroup_register_region() to the raw
dmem_cgroup_register_region() and store the region in
amdgpu_vram_mgr.cg_region. Call dmem_cgroup_unregister_region()
in amdgpu_vram_mgr_fini() after ttm_resource_manager_evict_all()
to drain in-flight reclaim callbacks, and clear man->cg afterwards.
This is required because amdgpu's vram manager fini is called
explicitly during driver unbind, which may precede the DRM device
release and thus precede any drmm-based cleanup. (Sashiko-bot)
v6:
- Fix mgr->cg_region never being assigned, so
dmem_cgroup_unregister_region() in fini silently no-ops on NULL
and leaks the region. (Sashiko-bot)
- Reorder fini to call set_used(false) and evict_all() before
dmem_cgroup_unregister_region(), so ttm_resource_free() can
uncharge via man->cg during eviction; clear man->cg after
unregister. (Sashiko-bot)
v7:
- Move dmem_cgroup_unregister_region() before the early return on
evict_all() failure; not doing so leaves a dangling reclaim callback
pointing to the partially-torn-down VRAM manager, causing a
use-after-free when the cgroup later triggers reclaim. (Sashiko-bot)
- Switch back to drmm_cgroup_register_region() with a drm_dev_enter/
exit guard in the reclaim callback (matching xe), rather than manual
register/unregister. drm_dev_unplug() fires before vram_mgr_fini(),
so drm_dev_enter() returning false prevents any reclaim from touching
the manager during teardown. This also fixes the "vram" name
collision on multi-GPU systems, since drmm_cgroup_register_region()
automatically prefixes with "drm/<pci-addr>/". (Sashiko-bot)
v8:
- Move the dmem cgroup region teardown back into
amdgpu_vram_mgr_fini(): register the region with
dmem_cgroup_register_region() (keeping the "drm/<unique>/vram"
prefix), store it in amdgpu_vram_mgr.cg_region, and unregister it
explicitly after ttm_resource_manager_evict_all(). The v7
drmm-only approach left a use-after-free on the probe-error
teardown path: drm_dev_unplug() is not called there, so the
drm_dev_enter() guard stays open while drm_driver.release destroys
the manager before the drmm action unregisters the region. The
explicit unregister drains in-flight reclaim on every teardown
path; the drm_dev_enter() guard is kept as defense against reclaim
after unplug. (Sashiko-bot)
Assisted-by: GitHub_Copilot:claude-sonnet-4.6
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 51 ++++++++++++++++++--
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 3 ++
3 files changed, 50 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 7920675af1d1..b46b1d19349e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -1507,7 +1507,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
dma_resv_for_each_fence(&resv_cursor, bo->base.resv,
DMA_RESV_USAGE_BOOKKEEP, f) {
if (amdkfd_fence_check_mm(f, current->mm) &&
- !(place->flags & TTM_PL_FLAG_CONTIGUOUS))
+ !(place && (place->flags & TTM_PL_FLAG_CONTIGUOUS)))
return false;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 08f05c3aed1d..8c62f4681d65 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -906,6 +906,28 @@ static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
.debug = amdgpu_vram_mgr_debug
};
+static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops;
+
+static int amdgpu_vram_mgr_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
+ u64 target_bytes, void *priv)
+{
+ struct ttm_resource_manager *man = priv;
+ struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
+ int ret, idx;
+
+ if (!drm_dev_enter(adev_to_drm(adev), &idx))
+ return -ENODEV;
+
+ ret = ttm_resource_manager_dmem_reclaim(pool, target_bytes, priv);
+
+ drm_dev_exit(idx);
+ return ret;
+}
+
+static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops = {
+ .reclaim = amdgpu_vram_mgr_dmem_reclaim,
+};
+
/**
* amdgpu_vram_mgr_init - init VRAM manager and DRM MM
*
@@ -917,6 +939,7 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
{
struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
struct ttm_resource_manager *man = &mgr->manager;
+ struct dmem_cgroup_region *cg;
int err;
ttm_resource_manager_init(man, &adev->mman.bdev,
@@ -933,12 +956,17 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
if (err)
return err;
- man->cg = drmm_cgroup_register_region(adev_to_drm(adev), "vram",
- &(struct dmem_cgroup_init){
+ cg = dmem_cgroup_register_region(&(struct dmem_cgroup_init){
.size = adev->gmc.real_vram_size,
- });
- if (IS_ERR(man->cg))
- return PTR_ERR(man->cg);
+ .ops = &amdgpu_vram_mgr_dmem_ops,
+ .reclaim_priv = man,
+ },
+ "drm/%s/vram", adev_to_drm(adev)->unique);
+ if (IS_ERR(cg))
+ return PTR_ERR(cg);
+
+ mgr->cg_region = cg;
+ ttm_resource_manager_set_dmem_region(man, cg);
ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
ttm_resource_manager_set_used(man, true);
@@ -963,6 +991,19 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
ttm_resource_manager_set_used(man, false);
ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
+
+ /*
+ * Unregister the dmem cgroup region regardless of the evict_all()
+ * result and before any further teardown. This drains in-flight
+ * reclaim callbacks and blocks new ones, so no reclaim can reference
+ * the manager once we start freeing it. It must run after evict_all()
+ * so that ttm_resource_free() can still uncharge via man->cg during
+ * eviction. Clear man->cg afterwards.
+ */
+ dmem_cgroup_unregister_region(mgr->cg_region);
+ mgr->cg_region = NULL;
+ ttm_resource_manager_set_dmem_region(man, NULL);
+
if (ret)
return;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
index 429a21a2e9b2..e581cbf52fcb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
@@ -26,6 +26,8 @@
#include <linux/gpu_buddy.h>
+struct dmem_cgroup_region;
+
struct amdgpu_vram_mgr {
struct ttm_resource_manager manager;
struct gpu_buddy mm;
@@ -36,6 +38,7 @@ struct amdgpu_vram_mgr {
atomic64_t vis_usage;
u64 default_page_size;
struct list_head allocated_vres_list;
+ struct dmem_cgroup_region *cg_region;
};
struct amdgpu_vres_task {
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v8 3/6] cgroup/dmem: Add reclaim callback for lowering max below current usage
2026-07-23 10:03 ` [PATCH v8 3/6] cgroup/dmem: Add reclaim callback for lowering max below current usage Thomas Hellström
@ 2026-07-23 10:21 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-07-23 10:21 UTC (permalink / raw)
To: Thomas Hellström; +Cc: tj, hannes, mkoutny, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Unbounded SRCU read lock hold time in set_resource_max() can stall unregistration indefinitely
Pre-existing issues:
- [High] 32-bit integer overflow and truncation in dmem cgroup limits and accounting
--
--- Patch [3]: [PATCH v8 3/6] cgroup/dmem: Add reclaim callback for lowering max below current usage ---
commit 1477e3308e9932d9b9ab70b4c6666ef7191157d5
Author: Thomas Hellström <thomas.hellstrom@linux.intel.com>
cgroup/dmem: Add reclaim callback for lowering max below current usage
This commit adds an optional reclaim callback to dmem_cgroup_region. When
dmem.max is lowered below current usage, the driver is asked to evict memory,
and concurrent allocations are throttled. It introduces an SRCU domain to
serialize these reclaim callbacks against region unregistration.
> diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
> index eb46e99b73666..7e427895f23ea 100644
> --- a/kernel/cgroup/dmem.c
> +++ b/kernel/cgroup/dmem.c
[ ... ]
> @@ -145,21 +161,52 @@ static void free_cg_pool(struct dmem_cgroup_pool_state *pool)
> }
>
> 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;
[Severity: High]
This isn't a bug introduced by this patch, but does this truncation break
cgroup limits on 32-bit systems?
The dmem subsystem appears to be tracking bytes rather than pages using the
page_counter API. On 32-bit kernels, an unsigned long is 32 bits, which
means any limit or usage exceeding 4GB will be silently truncated when a
u64 is cast to unsigned long in set_resource_max().
This same issue seems to apply in dmem_cgroup_try_charge() where the u64
size argument is passed to page_counter_try_charge():
kernel/cgroup/dmem.c:dmem_cgroup_try_charge() {
...
if (!page_counter_try_charge(&pool->cnt, size, &fail)) {
...
}
If the allocation exceeds 4GB, or if the total usage tracked in the
atomic_long_t exceeds 4GB, would this cause the counter to wrap and
silently bypass the limits?
> +
> + /* 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);
> }
[Severity: High]
Can this loop stall indefinitely and block region unregistration?
In set_resource_max(), if region->ops->reclaim() continually successfully
frees some memory but not enough to fall below the limit, it returns 0.
When it returns 0, the retries counter is not decremented:
if (ret && (ret != -ENOSPC || !retries--))
break;
Since srcu_read_lock(&dmemcg_srcu) is held for the entire duration of this
retry loop, an infinite loop here would indefinitely hold the SRCU read
lock.
If a cgroup administrator sets dmem.max below current usage while
concurrent processes continually allocate memory, could this block the
synchronize_srcu() call in dmem_cgroup_unregister_region() forever,
hanging the system during device hot-unplug or module unload?
Would it be safer to periodically drop and reacquire the SRCU read lock
inside the loop, or limit the total number of retries regardless of the
return code?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723100350.16895-1-thomas.hellstrom@linux.intel.com?part=3
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 1/6] drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init()
2026-07-23 10:03 ` [PATCH v8 1/6] drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init() Thomas Hellström
@ 2026-07-23 10:23 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-07-23 10:23 UTC (permalink / raw)
To: Thomas Hellström; +Cc: mkoutny, hannes, tj, dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Incomplete Fix: Teardown path still crashes on VRAM init failure (Null Pointer Dereference)
- [High] Use-After-Free due to skipped `ttm_device_fini` on `amdgpu_ttm_pools_init` failure
--
--- Patch [1]: [PATCH v8 1/6] drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init() ---
commit b8b31530c66aa0b0a491f59f8e3765cadbed921e
Author: Thomas Hellström <thomas.hellstrom@linux.intel.com>
drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init()
The commit moves drmm_cgroup_register_region() after the initialization of
the resource manager and buddy allocator in amdgpu_vram_mgr_init(). This
prevents NULL pointer dereferences in amdgpu_vram_mgr_fini() when teardown
is triggered following an initialization failure.
Closes: https://sashiko.dev/#/patchset/20260428073116.15687-1-thomas.hellstrom@linux.intel.com?part=4
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
> index 2a241a5b12c42..ac3f71d77140a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
[ ... ]
> @@ -935,6 +932,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);
> + if (IS_ERR(man->cg))
> + return PTR_ERR(man->cg);
[Severity: High]
This isn't a bug introduced by this patch, but it looks like the teardown
path will still crash if drmm_cgroup_register_region() or gpu_buddy_init()
fails.
Because adev->mman.initialized is set to true before amdgpu_vram_mgr_init()
is called, an error here propagates up and triggers amdgpu_ttm_fini() during
device teardown.
amdgpu_ttm_fini() unconditionally calls teardown for managers that were never
initialized:
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c:amdgpu_ttm_fini() {
...
amdgpu_gtt_mgr_fini(adev);
amdgpu_preempt_mgr_fini(adev);
...
}
Because these managers were never initialized, man->lru is zeroed out. When
ttm_resource_manager_evict_all() calls ttm_bo_evict_first(), it leads to
ttm_resource_manager_first() executing:
drivers/gpu/drm/ttm/ttm_resource.c:ttm_resource_manager_first() {
...
list_move(&cursor->hitch.link, &man->lru[cursor->priority]);
...
}
Since man->lru[0] is zero-initialized, man->lru[0].next is NULL, which causes
list_move() to dereference NULL and crash the kernel.
Furthermore, if gpu_buddy_init() itself fails, it leaves mm->n_roots set to a
non-zero value but frees or zeroes mm->roots:
drivers/gpu/buddy.c:gpu_buddy_init() {
...
mm->n_roots = hweight64(size);
mm->roots = kmalloc_array(mm->n_roots, ...);
if (!mm->roots)
goto out_free_tree;
...
}
When amdgpu_vram_mgr_fini() then calls gpu_buddy_fini(), will it dereference
the dangling or NULL mm->roots array?
Could amdgpu_ttm_fini() be updated with additional guards to prevent cleaning
up uninitialized managers?
[Severity: High]
This is a pre-existing issue, but I noticed another problem in the
amdgpu_ttm_init() failure path that might be worth addressing.
If amdgpu_ttm_pools_init() fails early in amdgpu_ttm_init(), it returns
immediately:
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c:amdgpu_ttm_init() {
...
r = amdgpu_ttm_pools_init(adev);
if (r) {
...
return r;
}
adev->mman.initialized = true;
...
}
This means adev->mman.initialized remains false. However, ttm_device_init()
was already called and successfully linked the device into the global list:
drivers/gpu/drm/ttm/ttm_device.c:ttm_device_init() {
...
list_add_tail(&bdev->device_list, &glob->device_list);
...
}
When amdgpu_ttm_fini() runs during teardown, it skips ttm_device_fini()
because initialized is false:
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c:amdgpu_ttm_fini() {
...
if (!adev->mman.initialized)
return;
...
ttm_device_fini(&adev->mman.bdev);
...
}
This leaves a dangling list entry in ttm_glob.device_list. When
ttm_global_swapout() is later triggered by memory pressure, will it traverse
the list and dereference the freed amdgpu_device memory, causing a
use-after-free?
> +
> ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
> ttm_resource_manager_set_used(man, true);
> return 0;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723100350.16895-1-thomas.hellstrom@linux.intel.com?part=1
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller
2026-07-23 10:03 ` [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller Thomas Hellström
@ 2026-07-23 10:31 ` sashiko-bot
2026-07-23 12:02 ` Maarten Lankhorst
1 sibling, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-07-23 10:31 UTC (permalink / raw)
To: Thomas Hellström; +Cc: dri-devel, tj, mkoutny, hannes
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] ttm_resource_manager_set_dmem_region(man, NULL) fails to prevent a Use-After-Free in the reclaim callback when the dmem region outlives the resource manager.
- [High] AMDGPU's eviction_valuable callback dereferences the `place` pointer without checking for NULL, which crashes during cgroup reclaim.
- [High] Incorrect check in `ttm_resource_free()` causes cgroup charge leaks when a region is detached, or potential crashes when a region is attached post-allocation.
--
--- Patch [4]: [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller ---
commit 2a3c858c74bfd2816b989356ca73920f98d725df
Author: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Subject: drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller
This commit introduces a cgroup-aware reclaim callback for the TTM dmem
controller to evict buffer objects based on cgroup pools. It adds a new
sleeping lock mode for the LRU walker and provides functions to associate
dmem regions with resource managers.
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
[ ... ]
> @@ -515,12 +515,20 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
[ ... ]
> + /*
> + * evict_walk->place is NULL in cgroup drain mode. Drivers'
> + * eviction_valuable() callbacks must handle a NULL place, treating it
> + * as "any placement": the TTM base implementation already does so via
> + * ttm_resource_intersects().
> + */
> if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place))
> return 0;
[Severity: High]
Will this crash in AMDGPU when it evaluates KFD fences?
While the TTM base implementation handles a NULL place, the AMDGPU
implementation does not seem to do so. In amdgpu_ttm_bo_eviction_valuable(),
the place pointer is unconditionally dereferenced:
amdgpu_ttm_bo_eviction_valuable()
if (amdkfd_fence_check_mm(f, current->mm) &&
!(place->flags & TTM_PL_FLAG_CONTIGUOUS))
return false;
Does the driver callback need to be updated to handle the NULL place during
cgroup drain, or should TTM provide a dummy place?
[ ... ]
> diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
> --- a/drivers/gpu/drm/ttm/ttm_resource.c
> +++ b/drivers/gpu/drm/ttm/ttm_resource.c
[ ... ]
> @@ -953,3 +953,55 @@ void ttm_resource_manager_create_debugfs(struct ttm_resource_manager *man,
[ ... ]
> +void ttm_resource_manager_set_dmem_region(struct ttm_resource_manager *man,
> + struct dmem_cgroup_region *region)
> +{
> + if (!IS_ERR(region))
> + man->cg = region;
[Severity: High]
Does setting the region to NULL properly detach the reclaim callback?
When ttm_resource_manager_set_dmem_region() is called with a NULL region to
detach it before teardown, it clears man->cg, but it doesn't appear to
unregister the callback from the cgroup region. If the manager is destroyed
before the region, could background reclaim or sysfs writes to dmem.max
invoke the callback with a dangling priv pointer?
Additionally, can modifying man->cg here cause cgroup charge leaks when
resources are freed?
Looking at ttm_resource_free(), the uncharge path checks man->cg instead of
the resource's pool:
ttm_resource_free()
pool = (*res)->css;
man = ttm_manager_type(bo->bdev, (*res)->mem_type);
man->func->free(man, *res);
*res = NULL;
if (man->cg)
dmem_cgroup_uncharge(pool, bo->base.size);
If a region is detached (man->cg becomes NULL) after a resource was
allocated, it skips uncharging a valid pool pointer, permanently leaking the
charge. Conversely, if man->cg is attached after allocation (so pool is
NULL), it might call dmem_cgroup_uncharge() with a NULL pool.
Should ttm_resource_free() check if the resource itself has a valid css pool
rather than checking man->cg?
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723100350.16895-1-thomas.hellstrom@linux.intel.com?part=4
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 6/6] drm/amdgpu: Wire up dmem cgroup reclaim for VRAM manager
2026-07-23 10:03 ` [PATCH v8 6/6] drm/amdgpu: " Thomas Hellström
@ 2026-07-23 10:50 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-07-23 10:50 UTC (permalink / raw)
To: Thomas Hellström; +Cc: tj, hannes, dri-devel, mkoutny
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Memory Leak and Use-After-Free of cgroup region and gpu_buddy on probe failure
- [High] Permanent memory charge leak on VRAM eviction failure
- [Medium] Commit Message and Implementation Mismatch regarding cgroup region registration
--
--- Patch [6]: [PATCH v8 6/6] drm/amdgpu: Wire up dmem cgroup reclaim for VRAM manager ---
commit 9102e928a842cf958ce390fd437331e21fe61836
Author: Thomas Hellström <thomas.hellstrom@linux.intel.com>
drm/amdgpu: Wire up dmem cgroup reclaim for VRAM manager
Register the VRAM manager with the dmem cgroup reclaim infrastructure
so that lowering dmem.max below current VRAM usage triggers TTM
eviction rather than failing with -EBUSY.
> Use drmm_cgroup_register_region() so that the region is automatically
> unregistered at DRM device release, after drm_dev_unplug() has already
> made drm_dev_enter() return false.
[Severity: Medium]
Is this description still accurate? The commit message claims that
drmm_cgroup_register_region() is used to automatically tie the cgroup
region's lifecycle to the DRM device release, but the code implements
manual registration using dmem_cgroup_register_region().
The v8 changelog at the bottom accurately describes why this manual approach
was chosen, but the main body of the commit message appears to still have
the older description.
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
[ ... ]
> @@ -917,6 +939,7 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
> {
> struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
> struct ttm_resource_manager *man = &mgr->manager;
> + struct dmem_cgroup_region *cg;
> int err;
>
> ttm_resource_manager_init(man, &adev->mman.bdev,
> @@ -933,12 +956,17 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
> if (err)
> return err;
>
> - man->cg = drmm_cgroup_register_region(adev_to_drm(adev), "vram",
> - &(struct dmem_cgroup_init){
> + cg = dmem_cgroup_register_region(&(struct dmem_cgroup_init){
> .size = adev->gmc.real_vram_size,
> - });
> - if (IS_ERR(man->cg))
> - return PTR_ERR(man->cg);
> + .ops = &amdgpu_vram_mgr_dmem_ops,
> + .reclaim_priv = man,
> + },
> + "drm/%s/vram", adev_to_drm(adev)->unique);
> + if (IS_ERR(cg))
> + return PTR_ERR(cg);
[Severity: High]
Does this early return leak the gpu_buddy allocator? It looks like
gpu_buddy_init() succeeds just before this, but gpu_buddy_fini() is not
called if dmem_cgroup_register_region() fails.
Also, if amdgpu_vram_mgr_init() succeeds but a subsequent step in the GMC
block's sw_init fails:
amdgpu_device_ip_init() {
r = adev->ip_blocks[i].version->funcs->sw_init(&adev->ip_blocks[i]);
if (r) {
goto init_failed;
}
adev->ip_blocks[i].status.sw = true;
}
The status.sw flag is not set, causing amdgpu_device_ip_fini() to skip
sw_fini and bypass all cleanup. This would permanently leak the gpu_buddy
structures and the registered cgroup region.
Because the cgroup region remains active and its reclaim_priv points to the
manager inside the freed amdgpu_device structure, could a subsequent cgroup
memory pressure event trigger a use-after-free on the dangling pointer?
> +
> + mgr->cg_region = cg;
> + ttm_resource_manager_set_dmem_region(man, cg);
>
> ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
> ttm_resource_manager_set_used(man, true);
[ ... ]
> @@ -963,6 +991,19 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
> ttm_resource_manager_set_used(man, false);
>
> ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
> +
> + /*
> + * Unregister the dmem cgroup region regardless of the evict_all()
> + * result and before any further teardown. This drains in-flight
> + * reclaim callbacks and blocks new ones, so no reclaim can reference
> + * the manager once we start freeing it. It must run after evict_all()
> + * so that ttm_resource_free() can still uncharge via man->cg during
> + * eviction. Clear man->cg afterwards.
> + */
> + dmem_cgroup_unregister_region(mgr->cg_region);
> + mgr->cg_region = NULL;
> + ttm_resource_manager_set_dmem_region(man, NULL);
> +
> if (ret)
> return;
[Severity: High]
Does this cause a permanent memory charge leak if eviction fails?
The unregistration happens and man->cg is cleared before returning early
on eviction failure. If eviction fails, buffer objects are left alive in
VRAM.
When these buffer objects are eventually freed, ttm_resource_free() relies
on man->cg being non-NULL to know whether it should call
dmem_cgroup_uncharge():
ttm_resource_free() {
if (man->cg)
dmem_cgroup_uncharge(pool, bo->base.size);
}
Since man->cg was already cleared, the uncharge is skipped, which appears
to leak the cgroup charge and its css reference permanently.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723100350.16895-1-thomas.hellstrom@linux.intel.com?part=6
^ permalink raw reply [flat|nested] 16+ messages in thread
* ✗ CI.checkpatch: warning for Add reclaim to the dmem cgroup controller (rev8)
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
` (5 preceding siblings ...)
2026-07-23 10:03 ` [PATCH v8 6/6] drm/amdgpu: " Thomas Hellström
@ 2026-07-23 11:47 ` Patchwork
2026-07-23 11:48 ` ✓ CI.KUnit: success " Patchwork
2026-07-23 12:29 ` ✓ Xe.CI.BAT: " Patchwork
8 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2026-07-23 11:47 UTC (permalink / raw)
To: Thomas Hellström; +Cc: intel-xe
== Series Details ==
Series: Add reclaim to the dmem cgroup controller (rev8)
URL : https://patchwork.freedesktop.org/series/163970/
State : warning
== Summary ==
+ KERNEL=/kernel
+ git clone https://gitlab.freedesktop.org/drm/maintainer-tools mt
Cloning into 'mt'...
warning: redirecting to https://gitlab.freedesktop.org/drm/maintainer-tools.git/
+ git -C mt rev-list -n1 origin/master
061140b9bc586ae7f40abc1249c97e1cc72d1b9d
+ cd /kernel
+ git config --global --add safe.directory /kernel
+ git log -n1
commit ed4facacb54248512464d2c638759fc700e4bd35
Author: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Date: Thu Jul 23 12:03:50 2026 +0200
drm/amdgpu: Wire up dmem cgroup reclaim for VRAM manager
Register the VRAM manager with the dmem cgroup reclaim infrastructure
so that lowering dmem.max below current VRAM usage triggers TTM
eviction rather than failing with -EBUSY.
Guard place->flags in amdgpu_ttm_bo_eviction_valuable() against NULL,
as the TTM reclaim path passes a NULL place in cgroup drain mode.
Use drmm_cgroup_register_region() so that the region is automatically
unregistered at DRM device release, after drm_dev_unplug() has already
made drm_dev_enter() return false. The drm_dev_enter/exit guard in the
reclaim callback ensures no reclaim work touches the TTM manager after
driver unbind, closing the window between vram_mgr_fini() (called from
drm_driver.release) and the drmm cleanup that unregisters the region.
v3:
- Rebased on fix for uninitialized list and buddy allocator on the
drmm_cgroup_register_region() error path.
v5:
- Rebased on the introduction of struct dmem_cgroup_init.
- Clear the reclaim callback in amdgpu_vram_mgr_fini() to prevent
use-after-free if cgroup reclaim is triggered after driver unbind
while userspace holds an open DRM file descriptor. (Sashiko-bot)
- Switch from drmm_cgroup_register_region() to the raw
dmem_cgroup_register_region() and store the region in
amdgpu_vram_mgr.cg_region. Call dmem_cgroup_unregister_region()
in amdgpu_vram_mgr_fini() after ttm_resource_manager_evict_all()
to drain in-flight reclaim callbacks, and clear man->cg afterwards.
This is required because amdgpu's vram manager fini is called
explicitly during driver unbind, which may precede the DRM device
release and thus precede any drmm-based cleanup. (Sashiko-bot)
v6:
- Fix mgr->cg_region never being assigned, so
dmem_cgroup_unregister_region() in fini silently no-ops on NULL
and leaks the region. (Sashiko-bot)
- Reorder fini to call set_used(false) and evict_all() before
dmem_cgroup_unregister_region(), so ttm_resource_free() can
uncharge via man->cg during eviction; clear man->cg after
unregister. (Sashiko-bot)
v7:
- Move dmem_cgroup_unregister_region() before the early return on
evict_all() failure; not doing so leaves a dangling reclaim callback
pointing to the partially-torn-down VRAM manager, causing a
use-after-free when the cgroup later triggers reclaim. (Sashiko-bot)
- Switch back to drmm_cgroup_register_region() with a drm_dev_enter/
exit guard in the reclaim callback (matching xe), rather than manual
register/unregister. drm_dev_unplug() fires before vram_mgr_fini(),
so drm_dev_enter() returning false prevents any reclaim from touching
the manager during teardown. This also fixes the "vram" name
collision on multi-GPU systems, since drmm_cgroup_register_region()
automatically prefixes with "drm/<pci-addr>/". (Sashiko-bot)
v8:
- Move the dmem cgroup region teardown back into
amdgpu_vram_mgr_fini(): register the region with
dmem_cgroup_register_region() (keeping the "drm/<unique>/vram"
prefix), store it in amdgpu_vram_mgr.cg_region, and unregister it
explicitly after ttm_resource_manager_evict_all(). The v7
drmm-only approach left a use-after-free on the probe-error
teardown path: drm_dev_unplug() is not called there, so the
drm_dev_enter() guard stays open while drm_driver.release destroys
the manager before the drmm action unregisters the region. The
explicit unregister drains in-flight reclaim on every teardown
path; the drm_dev_enter() guard is kept as defense against reclaim
after unplug. (Sashiko-bot)
Assisted-by: GitHub_Copilot:claude-sonnet-4.6
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+ /mt/dim checkpatch 2c64192f1ad194a53800f6dd8c779d5b4bbc1831 drm-intel
ed174c7e12a8 drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init()
f296621a568c cgroup/dmem: Introduce struct dmem_cgroup_init for region initialization
4f9361555a87 cgroup/dmem: Add reclaim callback for lowering max below current usage
eb3905d002d5 drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller
-:154: CHECK:MULTIPLE_ASSIGNMENTS: multiple assignments should be avoided
#154: FILE: drivers/gpu/drm/ttm/ttm_bo.c:679:
+ evict_walk.try_low = evict_walk.hit_low = false;
total: 0 errors, 0 warnings, 1 checks, 226 lines checked
0c9edfb67f63 drm/xe: Wire up dmem cgroup reclaim for VRAM manager
-:43: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#43: FILE: drivers/gpu/drm/xe/xe_ttm_vram_mgr.c:282:
+static int xe_ttm_vram_mgr_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
+ u64 target_bytes, void *priv)
total: 0 errors, 0 warnings, 1 checks, 75 lines checked
ed4facacb542 drm/amdgpu: Wire up dmem cgroup reclaim for VRAM manager
^ permalink raw reply [flat|nested] 16+ messages in thread
* ✓ CI.KUnit: success for Add reclaim to the dmem cgroup controller (rev8)
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
` (6 preceding siblings ...)
2026-07-23 11:47 ` ✗ CI.checkpatch: warning for Add reclaim to the dmem cgroup controller (rev8) Patchwork
@ 2026-07-23 11:48 ` Patchwork
2026-07-23 12:29 ` ✓ Xe.CI.BAT: " Patchwork
8 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2026-07-23 11:48 UTC (permalink / raw)
To: Thomas Hellström; +Cc: intel-xe
== Series Details ==
Series: Add reclaim to the dmem cgroup controller (rev8)
URL : https://patchwork.freedesktop.org/series/163970/
State : success
== Summary ==
+ trap cleanup EXIT
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/xe/.kunitconfig
[11:47:29] Configuring KUnit Kernel ...
Generating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[11:47:34] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[11:48:06] Starting KUnit Kernel (1/1)...
[11:48:06] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[11:48:06] ================== guc_buf (11 subtests) ===================
[11:48:06] [PASSED] test_smallest
[11:48:06] [PASSED] test_largest
[11:48:06] [PASSED] test_granular
[11:48:06] [PASSED] test_unique
[11:48:06] [PASSED] test_overlap
[11:48:06] [PASSED] test_reusable
[11:48:06] [PASSED] test_too_big
[11:48:06] [PASSED] test_flush
[11:48:06] [PASSED] test_lookup
[11:48:06] [PASSED] test_data
[11:48:06] [PASSED] test_class
[11:48:06] ===================== [PASSED] guc_buf =====================
[11:48:06] =================== guc_dbm (7 subtests) ===================
[11:48:06] [PASSED] test_empty
[11:48:06] [PASSED] test_default
[11:48:06] ======================== test_size ========================
[11:48:06] [PASSED] 4
[11:48:06] [PASSED] 8
[11:48:06] [PASSED] 32
[11:48:06] [PASSED] 256
[11:48:06] ==================== [PASSED] test_size ====================
[11:48:06] ======================= test_reuse ========================
[11:48:06] [PASSED] 4
[11:48:06] [PASSED] 8
[11:48:06] [PASSED] 32
[11:48:06] [PASSED] 256
[11:48:06] =================== [PASSED] test_reuse ====================
[11:48:06] =================== test_range_overlap ====================
[11:48:06] [PASSED] 4
[11:48:06] [PASSED] 8
[11:48:06] [PASSED] 32
[11:48:06] [PASSED] 256
[11:48:06] =============== [PASSED] test_range_overlap ================
[11:48:06] =================== test_range_compact ====================
[11:48:06] [PASSED] 4
[11:48:06] [PASSED] 8
[11:48:06] [PASSED] 32
[11:48:06] [PASSED] 256
[11:48:06] =============== [PASSED] test_range_compact ================
[11:48:06] ==================== test_range_spare =====================
[11:48:06] [PASSED] 4
[11:48:06] [PASSED] 8
[11:48:06] [PASSED] 32
[11:48:06] [PASSED] 256
[11:48:06] ================ [PASSED] test_range_spare =================
[11:48:06] ===================== [PASSED] guc_dbm =====================
[11:48:06] =================== guc_idm (6 subtests) ===================
[11:48:06] [PASSED] bad_init
[11:48:06] [PASSED] no_init
[11:48:06] [PASSED] init_fini
[11:48:06] [PASSED] check_used
[11:48:06] [PASSED] check_quota
[11:48:06] [PASSED] check_all
[11:48:06] ===================== [PASSED] guc_idm =====================
[11:48:06] =============== guc_klv_helpers (9 subtests) ===============
[11:48:06] [PASSED] test_count
[11:48:06] [PASSED] test_encode_u32
[11:48:06] [PASSED] test_encode_u64
[11:48:06] [PASSED] test_encode_string
[11:48:06] [PASSED] test_encode_object_raw
[11:48:06] [PASSED] test_encode_object_klv
[11:48:06] [PASSED] test_encode_object_nested
[11:48:06] [PASSED] test_encode_object_basic
[11:48:06] [PASSED] test_print
[11:48:06] ================= [PASSED] guc_klv_helpers =================
[11:48:06] ================== no_relay (3 subtests) ===================
[11:48:06] [PASSED] xe_drops_guc2pf_if_not_ready
[11:48:06] [PASSED] xe_drops_guc2vf_if_not_ready
[11:48:06] [PASSED] xe_rejects_send_if_not_ready
[11:48:06] ==================== [PASSED] no_relay =====================
[11:48:06] ================== pf_relay (14 subtests) ==================
[11:48:06] [PASSED] pf_rejects_guc2pf_too_short
[11:48:06] [PASSED] pf_rejects_guc2pf_too_long
[11:48:06] [PASSED] pf_rejects_guc2pf_no_payload
[11:48:06] [PASSED] pf_fails_no_payload
[11:48:06] [PASSED] pf_fails_bad_origin
[11:48:06] [PASSED] pf_fails_bad_type
[11:48:06] [PASSED] pf_txn_reports_error
[11:48:06] [PASSED] pf_txn_sends_pf2guc
[11:48:06] [PASSED] pf_sends_pf2guc
[11:48:06] [SKIPPED] pf_loopback_nop (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[11:48:06] [SKIPPED] pf_loopback_echo (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[11:48:06] [SKIPPED] pf_loopback_fail (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[11:48:06] [SKIPPED] pf_loopback_busy (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[11:48:06] [SKIPPED] pf_loopback_retry (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[11:48:06] ==================== [PASSED] pf_relay =====================
[11:48:06] ================== vf_relay (3 subtests) ===================
[11:48:06] [PASSED] vf_rejects_guc2vf_too_short
[11:48:06] [PASSED] vf_rejects_guc2vf_too_long
[11:48:06] [PASSED] vf_rejects_guc2vf_no_payload
[11:48:06] ==================== [PASSED] vf_relay =====================
[11:48:06] ================ pf_gt_config (9 subtests) =================
[11:48:06] [PASSED] fair_contexts_1vf
[11:48:06] [PASSED] fair_doorbells_1vf
[11:48:06] [PASSED] fair_ggtt_1vf
[11:48:06] ====================== fair_vram_1vf ======================
[11:48:06] [PASSED] 3.50 GiB
[11:48:06] [PASSED] 11.5 GiB
[11:48:06] [PASSED] 15.5 GiB
[11:48:06] [PASSED] 31.5 GiB
[11:48:06] [PASSED] 63.5 GiB
[11:48:06] [PASSED] 1.91 GiB
[11:48:06] ================== [PASSED] fair_vram_1vf ==================
[11:48:06] ================ fair_vram_1vf_admin_only =================
[11:48:06] [PASSED] 3.50 GiB
[11:48:06] [PASSED] 11.5 GiB
[11:48:06] [PASSED] 15.5 GiB
[11:48:06] [PASSED] 31.5 GiB
[11:48:06] [PASSED] 63.5 GiB
[11:48:06] [PASSED] 1.91 GiB
[11:48:06] ============ [PASSED] fair_vram_1vf_admin_only =============
[11:48:06] ====================== fair_contexts ======================
[11:48:06] [PASSED] 1 VF
[11:48:06] [PASSED] 2 VFs
[11:48:06] [PASSED] 3 VFs
[11:48:06] [PASSED] 4 VFs
[11:48:06] [PASSED] 5 VFs
[11:48:06] [PASSED] 6 VFs
[11:48:06] [PASSED] 7 VFs
[11:48:06] [PASSED] 8 VFs
[11:48:06] [PASSED] 9 VFs
[11:48:06] [PASSED] 10 VFs
[11:48:06] [PASSED] 11 VFs
[11:48:06] [PASSED] 12 VFs
[11:48:06] [PASSED] 13 VFs
[11:48:06] [PASSED] 14 VFs
[11:48:06] [PASSED] 15 VFs
[11:48:06] [PASSED] 16 VFs
[11:48:06] [PASSED] 17 VFs
[11:48:06] [PASSED] 18 VFs
[11:48:06] [PASSED] 19 VFs
[11:48:06] [PASSED] 20 VFs
[11:48:06] [PASSED] 21 VFs
[11:48:06] [PASSED] 22 VFs
[11:48:06] [PASSED] 23 VFs
[11:48:06] [PASSED] 24 VFs
[11:48:06] [PASSED] 25 VFs
[11:48:06] [PASSED] 26 VFs
[11:48:06] [PASSED] 27 VFs
[11:48:06] [PASSED] 28 VFs
[11:48:06] [PASSED] 29 VFs
[11:48:06] [PASSED] 30 VFs
[11:48:06] [PASSED] 31 VFs
[11:48:06] [PASSED] 32 VFs
[11:48:06] [PASSED] 33 VFs
[11:48:06] [PASSED] 34 VFs
[11:48:06] [PASSED] 35 VFs
[11:48:06] [PASSED] 36 VFs
[11:48:06] [PASSED] 37 VFs
[11:48:06] [PASSED] 38 VFs
[11:48:06] [PASSED] 39 VFs
[11:48:06] [PASSED] 40 VFs
[11:48:06] [PASSED] 41 VFs
[11:48:06] [PASSED] 42 VFs
[11:48:06] [PASSED] 43 VFs
[11:48:06] [PASSED] 44 VFs
[11:48:06] [PASSED] 45 VFs
[11:48:06] [PASSED] 46 VFs
[11:48:06] [PASSED] 47 VFs
[11:48:06] [PASSED] 48 VFs
[11:48:06] [PASSED] 49 VFs
[11:48:06] [PASSED] 50 VFs
[11:48:06] [PASSED] 51 VFs
[11:48:06] [PASSED] 52 VFs
[11:48:06] [PASSED] 53 VFs
[11:48:06] [PASSED] 54 VFs
[11:48:06] [PASSED] 55 VFs
[11:48:06] [PASSED] 56 VFs
[11:48:06] [PASSED] 57 VFs
[11:48:06] [PASSED] 58 VFs
[11:48:06] [PASSED] 59 VFs
[11:48:06] [PASSED] 60 VFs
[11:48:06] [PASSED] 61 VFs
[11:48:06] [PASSED] 62 VFs
[11:48:06] [PASSED] 63 VFs
[11:48:06] ================== [PASSED] fair_contexts ==================
[11:48:06] ===================== fair_doorbells ======================
[11:48:06] [PASSED] 1 VF
[11:48:06] [PASSED] 2 VFs
[11:48:06] [PASSED] 3 VFs
[11:48:06] [PASSED] 4 VFs
[11:48:06] [PASSED] 5 VFs
[11:48:06] [PASSED] 6 VFs
[11:48:06] [PASSED] 7 VFs
[11:48:06] [PASSED] 8 VFs
[11:48:06] [PASSED] 9 VFs
[11:48:06] [PASSED] 10 VFs
[11:48:06] [PASSED] 11 VFs
[11:48:06] [PASSED] 12 VFs
[11:48:06] [PASSED] 13 VFs
[11:48:06] [PASSED] 14 VFs
[11:48:06] [PASSED] 15 VFs
[11:48:06] [PASSED] 16 VFs
[11:48:06] [PASSED] 17 VFs
[11:48:06] [PASSED] 18 VFs
[11:48:06] [PASSED] 19 VFs
[11:48:06] [PASSED] 20 VFs
[11:48:06] [PASSED] 21 VFs
[11:48:06] [PASSED] 22 VFs
[11:48:06] [PASSED] 23 VFs
[11:48:06] [PASSED] 24 VFs
[11:48:06] [PASSED] 25 VFs
[11:48:06] [PASSED] 26 VFs
[11:48:06] [PASSED] 27 VFs
[11:48:06] [PASSED] 28 VFs
[11:48:06] [PASSED] 29 VFs
[11:48:06] [PASSED] 30 VFs
[11:48:06] [PASSED] 31 VFs
[11:48:06] [PASSED] 32 VFs
[11:48:06] [PASSED] 33 VFs
[11:48:06] [PASSED] 34 VFs
[11:48:06] [PASSED] 35 VFs
[11:48:06] [PASSED] 36 VFs
[11:48:06] [PASSED] 37 VFs
[11:48:06] [PASSED] 38 VFs
[11:48:06] [PASSED] 39 VFs
[11:48:06] [PASSED] 40 VFs
[11:48:06] [PASSED] 41 VFs
[11:48:06] [PASSED] 42 VFs
[11:48:06] [PASSED] 43 VFs
[11:48:06] [PASSED] 44 VFs
[11:48:06] [PASSED] 45 VFs
[11:48:06] [PASSED] 46 VFs
[11:48:06] [PASSED] 47 VFs
[11:48:06] [PASSED] 48 VFs
[11:48:06] [PASSED] 49 VFs
[11:48:06] [PASSED] 50 VFs
[11:48:06] [PASSED] 51 VFs
[11:48:06] [PASSED] 52 VFs
[11:48:06] [PASSED] 53 VFs
[11:48:06] [PASSED] 54 VFs
[11:48:06] [PASSED] 55 VFs
[11:48:06] [PASSED] 56 VFs
[11:48:06] [PASSED] 57 VFs
[11:48:06] [PASSED] 58 VFs
[11:48:06] [PASSED] 59 VFs
[11:48:06] [PASSED] 60 VFs
[11:48:06] [PASSED] 61 VFs
[11:48:06] [PASSED] 62 VFs
[11:48:06] [PASSED] 63 VFs
[11:48:06] ================= [PASSED] fair_doorbells ==================
[11:48:06] ======================== fair_ggtt ========================
[11:48:06] [PASSED] 1 VF
[11:48:06] [PASSED] 2 VFs
[11:48:06] [PASSED] 3 VFs
[11:48:06] [PASSED] 4 VFs
[11:48:06] [PASSED] 5 VFs
[11:48:06] [PASSED] 6 VFs
[11:48:06] [PASSED] 7 VFs
[11:48:06] [PASSED] 8 VFs
[11:48:06] [PASSED] 9 VFs
[11:48:06] [PASSED] 10 VFs
[11:48:06] [PASSED] 11 VFs
[11:48:06] [PASSED] 12 VFs
[11:48:06] [PASSED] 13 VFs
[11:48:06] [PASSED] 14 VFs
[11:48:06] [PASSED] 15 VFs
[11:48:06] [PASSED] 16 VFs
[11:48:06] [PASSED] 17 VFs
[11:48:06] [PASSED] 18 VFs
[11:48:06] [PASSED] 19 VFs
[11:48:06] [PASSED] 20 VFs
[11:48:06] [PASSED] 21 VFs
[11:48:06] [PASSED] 22 VFs
[11:48:06] [PASSED] 23 VFs
[11:48:06] [PASSED] 24 VFs
[11:48:06] [PASSED] 25 VFs
[11:48:06] [PASSED] 26 VFs
[11:48:06] [PASSED] 27 VFs
[11:48:06] [PASSED] 28 VFs
[11:48:06] [PASSED] 29 VFs
[11:48:06] [PASSED] 30 VFs
[11:48:06] [PASSED] 31 VFs
[11:48:06] [PASSED] 32 VFs
[11:48:06] [PASSED] 33 VFs
[11:48:06] [PASSED] 34 VFs
[11:48:06] [PASSED] 35 VFs
[11:48:06] [PASSED] 36 VFs
[11:48:06] [PASSED] 37 VFs
[11:48:06] [PASSED] 38 VFs
[11:48:06] [PASSED] 39 VFs
[11:48:06] [PASSED] 40 VFs
[11:48:06] [PASSED] 41 VFs
[11:48:06] [PASSED] 42 VFs
[11:48:06] [PASSED] 43 VFs
[11:48:06] [PASSED] 44 VFs
[11:48:06] [PASSED] 45 VFs
[11:48:06] [PASSED] 46 VFs
[11:48:06] [PASSED] 47 VFs
[11:48:06] [PASSED] 48 VFs
[11:48:06] [PASSED] 49 VFs
[11:48:06] [PASSED] 50 VFs
[11:48:06] [PASSED] 51 VFs
[11:48:06] [PASSED] 52 VFs
[11:48:06] [PASSED] 53 VFs
[11:48:06] [PASSED] 54 VFs
[11:48:06] [PASSED] 55 VFs
[11:48:06] [PASSED] 56 VFs
[11:48:06] [PASSED] 57 VFs
[11:48:06] [PASSED] 58 VFs
[11:48:06] [PASSED] 59 VFs
[11:48:06] [PASSED] 60 VFs
[11:48:06] [PASSED] 61 VFs
[11:48:06] [PASSED] 62 VFs
[11:48:06] [PASSED] 63 VFs
[11:48:06] ==================== [PASSED] fair_ggtt ====================
[11:48:06] ======================== fair_vram ========================
[11:48:06] [PASSED] 1 VF
[11:48:06] [PASSED] 2 VFs
[11:48:06] [PASSED] 3 VFs
[11:48:06] [PASSED] 4 VFs
[11:48:06] [PASSED] 5 VFs
[11:48:06] [PASSED] 6 VFs
[11:48:06] [PASSED] 7 VFs
[11:48:06] [PASSED] 8 VFs
[11:48:06] [PASSED] 9 VFs
[11:48:06] [PASSED] 10 VFs
[11:48:06] [PASSED] 11 VFs
[11:48:06] [PASSED] 12 VFs
[11:48:06] [PASSED] 13 VFs
[11:48:06] [PASSED] 14 VFs
[11:48:06] [PASSED] 15 VFs
[11:48:06] [PASSED] 16 VFs
[11:48:06] [PASSED] 17 VFs
[11:48:06] [PASSED] 18 VFs
[11:48:06] [PASSED] 19 VFs
[11:48:06] [PASSED] 20 VFs
[11:48:06] [PASSED] 21 VFs
[11:48:06] [PASSED] 22 VFs
[11:48:06] [PASSED] 23 VFs
[11:48:06] [PASSED] 24 VFs
[11:48:06] [PASSED] 25 VFs
[11:48:06] [PASSED] 26 VFs
[11:48:06] [PASSED] 27 VFs
[11:48:06] [PASSED] 28 VFs
[11:48:06] [PASSED] 29 VFs
[11:48:06] [PASSED] 30 VFs
[11:48:06] [PASSED] 31 VFs
[11:48:06] [PASSED] 32 VFs
[11:48:06] [PASSED] 33 VFs
[11:48:06] [PASSED] 34 VFs
[11:48:06] [PASSED] 35 VFs
[11:48:06] [PASSED] 36 VFs
[11:48:06] [PASSED] 37 VFs
[11:48:06] [PASSED] 38 VFs
[11:48:06] [PASSED] 39 VFs
[11:48:06] [PASSED] 40 VFs
[11:48:06] [PASSED] 41 VFs
[11:48:06] [PASSED] 42 VFs
[11:48:06] [PASSED] 43 VFs
[11:48:06] [PASSED] 44 VFs
[11:48:06] [PASSED] 45 VFs
[11:48:06] [PASSED] 46 VFs
[11:48:06] [PASSED] 47 VFs
[11:48:06] [PASSED] 48 VFs
[11:48:06] [PASSED] 49 VFs
[11:48:06] [PASSED] 50 VFs
[11:48:06] [PASSED] 51 VFs
[11:48:06] [PASSED] 52 VFs
[11:48:06] [PASSED] 53 VFs
[11:48:06] [PASSED] 54 VFs
[11:48:06] [PASSED] 55 VFs
[11:48:06] [PASSED] 56 VFs
[11:48:06] [PASSED] 57 VFs
[11:48:06] [PASSED] 58 VFs
[11:48:06] [PASSED] 59 VFs
[11:48:07] [PASSED] 60 VFs
[11:48:07] [PASSED] 61 VFs
[11:48:07] [PASSED] 62 VFs
[11:48:07] [PASSED] 63 VFs
[11:48:07] ==================== [PASSED] fair_vram ====================
[11:48:07] ================== [PASSED] pf_gt_config ===================
[11:48:07] ===================== lmtt (1 subtest) =====================
[11:48:07] ======================== test_ops =========================
[11:48:07] [PASSED] 2-level
[11:48:07] [PASSED] multi-level
[11:48:07] ==================== [PASSED] test_ops =====================
[11:48:07] ====================== [PASSED] lmtt =======================
[11:48:07] ================= sriov_packet (1 subtest) =================
[11:48:07] [PASSED] test_descriptor_init
[11:48:07] ================== [PASSED] sriov_packet ===================
[11:48:07] ================= pf_service (11 subtests) =================
[11:48:07] [PASSED] pf_negotiate_any
[11:48:07] [PASSED] pf_negotiate_base_match
[11:48:07] [PASSED] pf_negotiate_base_newer
[11:48:07] [PASSED] pf_negotiate_base_next
[11:48:07] [SKIPPED] pf_negotiate_base_older (no older minor)
[11:48:07] [PASSED] pf_negotiate_base_prev
[11:48:07] [PASSED] pf_negotiate_latest_match
[11:48:07] [PASSED] pf_negotiate_latest_newer
[11:48:07] [PASSED] pf_negotiate_latest_next
[11:48:07] [SKIPPED] pf_negotiate_latest_older (no older minor)
[11:48:07] [SKIPPED] pf_negotiate_latest_prev (no prev major)
[11:48:07] =================== [PASSED] pf_service ====================
[11:48:07] ================= xe_guc_g2g (2 subtests) ==================
[11:48:07] ============== xe_live_guc_g2g_kunit_default ==============
[11:48:07] ========= [SKIPPED] xe_live_guc_g2g_kunit_default ==========
[11:48:07] ============== xe_live_guc_g2g_kunit_allmem ===============
[11:48:07] ========== [SKIPPED] xe_live_guc_g2g_kunit_allmem ==========
[11:48:07] =================== [SKIPPED] xe_guc_g2g ===================
[11:48:07] =================== xe_mocs (2 subtests) ===================
[11:48:07] ================ xe_live_mocs_kernel_kunit ================
[11:48:07] =========== [SKIPPED] xe_live_mocs_kernel_kunit ============
[11:48:07] ================ xe_live_mocs_reset_kunit =================
[11:48:07] ============ [SKIPPED] xe_live_mocs_reset_kunit ============
[11:48:07] ==================== [SKIPPED] xe_mocs =====================
[11:48:07] ================= xe_migrate (2 subtests) ==================
[11:48:07] ================= xe_migrate_sanity_kunit =================
[11:48:07] ============ [SKIPPED] xe_migrate_sanity_kunit =============
[11:48:07] ================== xe_validate_ccs_kunit ==================
[11:48:07] ============= [SKIPPED] xe_validate_ccs_kunit ==============
[11:48:07] =================== [SKIPPED] xe_migrate ===================
[11:48:07] ================== xe_dma_buf (1 subtest) ==================
[11:48:07] ==================== xe_dma_buf_kunit =====================
[11:48:07] ================ [SKIPPED] xe_dma_buf_kunit ================
[11:48:07] =================== [SKIPPED] xe_dma_buf ===================
[11:48:07] ================= xe_bo_shrink (1 subtest) =================
[11:48:07] =================== xe_bo_shrink_kunit ====================
[11:48:07] =============== [SKIPPED] xe_bo_shrink_kunit ===============
[11:48:07] ================== [SKIPPED] xe_bo_shrink ==================
[11:48:07] ==================== xe_bo (2 subtests) ====================
[11:48:07] ================== xe_ccs_migrate_kunit ===================
[11:48:07] ============== [SKIPPED] xe_ccs_migrate_kunit ==============
[11:48:07] ==================== xe_bo_evict_kunit ====================
[11:48:07] =============== [SKIPPED] xe_bo_evict_kunit ================
[11:48:07] ===================== [SKIPPED] xe_bo ======================
[11:48:07] ==================== args (13 subtests) ====================
[11:48:07] [PASSED] count_args_test
[11:48:07] [PASSED] call_args_example
[11:48:07] [PASSED] call_args_test
[11:48:07] [PASSED] drop_first_arg_example
[11:48:07] [PASSED] drop_first_arg_test
[11:48:07] [PASSED] first_arg_example
[11:48:07] [PASSED] first_arg_test
[11:48:07] [PASSED] last_arg_example
[11:48:07] [PASSED] last_arg_test
[11:48:07] [PASSED] pick_arg_example
[11:48:07] [PASSED] if_args_example
[11:48:07] [PASSED] if_args_test
[11:48:07] [PASSED] sep_comma_example
[11:48:07] ====================== [PASSED] args =======================
[11:48:07] =================== xe_pci (3 subtests) ====================
[11:48:07] ==================== check_graphics_ip ====================
[11:48:07] [PASSED] 12.00 Xe_LP
[11:48:07] [PASSED] 12.10 Xe_LP+
[11:48:07] [PASSED] 12.55 Xe_HPG
[11:48:07] [PASSED] 12.60 Xe_HPC
[11:48:07] [PASSED] 12.70 Xe_LPG
[11:48:07] [PASSED] 12.71 Xe_LPG
[11:48:07] [PASSED] 12.74 Xe_LPG+
[11:48:07] [PASSED] 20.01 Xe2_HPG
[11:48:07] [PASSED] 20.02 Xe2_HPG
[11:48:07] [PASSED] 20.04 Xe2_LPG
[11:48:07] [PASSED] 30.00 Xe3_LPG
[11:48:07] [PASSED] 30.01 Xe3_LPG
[11:48:07] [PASSED] 30.03 Xe3_LPG
[11:48:07] [PASSED] 30.04 Xe3_LPG
[11:48:07] [PASSED] 30.05 Xe3_LPG
[11:48:07] [PASSED] 35.10 Xe3p_LPG
[11:48:07] [PASSED] 35.11 Xe3p_XPC
[11:48:07] ================ [PASSED] check_graphics_ip ================
[11:48:07] ===================== check_media_ip ======================
[11:48:07] [PASSED] 12.00 Xe_M
[11:48:07] [PASSED] 12.55 Xe_HPM
[11:48:07] [PASSED] 13.00 Xe_LPM+
[11:48:07] [PASSED] 13.01 Xe2_HPM
[11:48:07] [PASSED] 20.00 Xe2_LPM
[11:48:07] [PASSED] 30.00 Xe3_LPM
[11:48:07] [PASSED] 30.02 Xe3_LPM
[11:48:07] [PASSED] 35.00 Xe3p_LPM
[11:48:07] [PASSED] 35.03 Xe3p_HPM
[11:48:07] ================= [PASSED] check_media_ip ==================
[11:48:07] =================== check_platform_desc ===================
[11:48:07] [PASSED] 0x9A60 (TIGERLAKE)
[11:48:07] [PASSED] 0x9A68 (TIGERLAKE)
[11:48:07] [PASSED] 0x9A70 (TIGERLAKE)
[11:48:07] [PASSED] 0x9A40 (TIGERLAKE)
[11:48:07] [PASSED] 0x9A49 (TIGERLAKE)
[11:48:07] [PASSED] 0x9A59 (TIGERLAKE)
[11:48:07] [PASSED] 0x9A78 (TIGERLAKE)
[11:48:07] [PASSED] 0x9AC0 (TIGERLAKE)
[11:48:07] [PASSED] 0x9AC9 (TIGERLAKE)
[11:48:07] [PASSED] 0x9AD9 (TIGERLAKE)
[11:48:07] [PASSED] 0x9AF8 (TIGERLAKE)
[11:48:07] [PASSED] 0x4C80 (ROCKETLAKE)
[11:48:07] [PASSED] 0x4C8A (ROCKETLAKE)
[11:48:07] [PASSED] 0x4C8B (ROCKETLAKE)
[11:48:07] [PASSED] 0x4C8C (ROCKETLAKE)
[11:48:07] [PASSED] 0x4C90 (ROCKETLAKE)
[11:48:07] [PASSED] 0x4C9A (ROCKETLAKE)
[11:48:07] [PASSED] 0x4680 (ALDERLAKE_S)
[11:48:07] [PASSED] 0x4682 (ALDERLAKE_S)
[11:48:07] [PASSED] 0x4688 (ALDERLAKE_S)
[11:48:07] [PASSED] 0x468A (ALDERLAKE_S)
[11:48:07] [PASSED] 0x468B (ALDERLAKE_S)
[11:48:07] [PASSED] 0x4690 (ALDERLAKE_S)
[11:48:07] [PASSED] 0x4692 (ALDERLAKE_S)
[11:48:07] [PASSED] 0x4693 (ALDERLAKE_S)
[11:48:07] [PASSED] 0x46A0 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46A1 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46A2 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46A3 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46A6 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46A8 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46AA (ALDERLAKE_P)
[11:48:07] [PASSED] 0x462A (ALDERLAKE_P)
[11:48:07] [PASSED] 0x4626 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x4628 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46B0 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46B1 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46B2 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46B3 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46C0 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46C1 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46C2 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46C3 (ALDERLAKE_P)
[11:48:07] [PASSED] 0x46D0 (ALDERLAKE_N)
[11:48:07] [PASSED] 0x46D1 (ALDERLAKE_N)
[11:48:07] [PASSED] 0x46D2 (ALDERLAKE_N)
[11:48:07] [PASSED] 0x46D3 (ALDERLAKE_N)
[11:48:07] [PASSED] 0x46D4 (ALDERLAKE_N)
[11:48:07] [PASSED] 0xA721 (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA7A1 (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA7A9 (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA7AC (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA7AD (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA720 (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA7A0 (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA7A8 (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA7AA (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA7AB (ALDERLAKE_P)
[11:48:07] [PASSED] 0xA780 (ALDERLAKE_S)
[11:48:07] [PASSED] 0xA781 (ALDERLAKE_S)
[11:48:07] [PASSED] 0xA782 (ALDERLAKE_S)
[11:48:07] [PASSED] 0xA783 (ALDERLAKE_S)
[11:48:07] [PASSED] 0xA788 (ALDERLAKE_S)
[11:48:07] [PASSED] 0xA789 (ALDERLAKE_S)
[11:48:07] [PASSED] 0xA78A (ALDERLAKE_S)
[11:48:07] [PASSED] 0xA78B (ALDERLAKE_S)
[11:48:07] [PASSED] 0x4905 (DG1)
[11:48:07] [PASSED] 0x4906 (DG1)
[11:48:07] [PASSED] 0x4907 (DG1)
[11:48:07] [PASSED] 0x4908 (DG1)
[11:48:07] [PASSED] 0x4909 (DG1)
[11:48:07] [PASSED] 0x56C0 (DG2)
[11:48:07] [PASSED] 0x56C2 (DG2)
[11:48:07] [PASSED] 0x56C1 (DG2)
[11:48:07] [PASSED] 0x7D51 (METEORLAKE)
[11:48:07] [PASSED] 0x7DD1 (METEORLAKE)
[11:48:07] [PASSED] 0x7D41 (METEORLAKE)
[11:48:07] [PASSED] 0x7D67 (METEORLAKE)
[11:48:07] [PASSED] 0xB640 (METEORLAKE)
[11:48:07] [PASSED] 0x56A0 (DG2)
[11:48:07] [PASSED] 0x56A1 (DG2)
[11:48:07] [PASSED] 0x56A2 (DG2)
[11:48:07] [PASSED] 0x56BE (DG2)
[11:48:07] [PASSED] 0x56BF (DG2)
[11:48:07] [PASSED] 0x5690 (DG2)
[11:48:07] [PASSED] 0x5691 (DG2)
[11:48:07] [PASSED] 0x5692 (DG2)
[11:48:07] [PASSED] 0x56A5 (DG2)
[11:48:07] [PASSED] 0x56A6 (DG2)
[11:48:07] [PASSED] 0x56B0 (DG2)
[11:48:07] [PASSED] 0x56B1 (DG2)
[11:48:07] [PASSED] 0x56BA (DG2)
[11:48:07] [PASSED] 0x56BB (DG2)
[11:48:07] [PASSED] 0x56BC (DG2)
[11:48:07] [PASSED] 0x56BD (DG2)
[11:48:07] [PASSED] 0x5693 (DG2)
[11:48:07] [PASSED] 0x5694 (DG2)
[11:48:07] [PASSED] 0x5695 (DG2)
[11:48:07] [PASSED] 0x56A3 (DG2)
[11:48:07] [PASSED] 0x56A4 (DG2)
[11:48:07] [PASSED] 0x56B2 (DG2)
[11:48:07] [PASSED] 0x56B3 (DG2)
[11:48:07] [PASSED] 0x5696 (DG2)
[11:48:07] [PASSED] 0x5697 (DG2)
[11:48:07] [PASSED] 0xB69 (PVC)
[11:48:07] [PASSED] 0xB6E (PVC)
[11:48:07] [PASSED] 0xBD4 (PVC)
[11:48:07] [PASSED] 0xBD5 (PVC)
[11:48:07] [PASSED] 0xBD6 (PVC)
[11:48:07] [PASSED] 0xBD7 (PVC)
[11:48:07] [PASSED] 0xBD8 (PVC)
[11:48:07] [PASSED] 0xBD9 (PVC)
[11:48:07] [PASSED] 0xBDA (PVC)
[11:48:07] [PASSED] 0xBDB (PVC)
[11:48:07] [PASSED] 0xBE0 (PVC)
[11:48:07] [PASSED] 0xBE1 (PVC)
[11:48:07] [PASSED] 0xBE5 (PVC)
[11:48:07] [PASSED] 0x7D40 (METEORLAKE)
[11:48:07] [PASSED] 0x7D45 (METEORLAKE)
[11:48:07] [PASSED] 0x7D55 (METEORLAKE)
[11:48:07] [PASSED] 0x7D60 (METEORLAKE)
[11:48:07] [PASSED] 0x7DD5 (METEORLAKE)
[11:48:07] [PASSED] 0x6420 (LUNARLAKE)
[11:48:07] [PASSED] 0x64A0 (LUNARLAKE)
[11:48:07] [PASSED] 0x64B0 (LUNARLAKE)
[11:48:07] [PASSED] 0xE202 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE209 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE20B (BATTLEMAGE)
[11:48:07] [PASSED] 0xE20C (BATTLEMAGE)
[11:48:07] [PASSED] 0xE20D (BATTLEMAGE)
[11:48:07] [PASSED] 0xE210 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE211 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE212 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE216 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE220 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE221 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE222 (BATTLEMAGE)
[11:48:07] [PASSED] 0xE223 (BATTLEMAGE)
[11:48:07] [PASSED] 0xB080 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB081 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB082 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB083 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB084 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB085 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB086 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB087 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB08F (PANTHERLAKE)
[11:48:07] [PASSED] 0xB090 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB0A0 (PANTHERLAKE)
[11:48:07] [PASSED] 0xB0B0 (PANTHERLAKE)
[11:48:07] [PASSED] 0xFD80 (PANTHERLAKE)
[11:48:07] [PASSED] 0xFD81 (PANTHERLAKE)
[11:48:07] [PASSED] 0xD740 (NOVALAKE_S)
[11:48:07] [PASSED] 0xD741 (NOVALAKE_S)
[11:48:07] [PASSED] 0xD742 (NOVALAKE_S)
[11:48:07] [PASSED] 0xD743 (NOVALAKE_S)
[11:48:07] [PASSED] 0xD745 (NOVALAKE_S)
[11:48:07] [PASSED] 0xD74A (NOVALAKE_S)
[11:48:07] [PASSED] 0xD74B (NOVALAKE_S)
[11:48:07] [PASSED] 0x674C (CRESCENTISLAND)
[11:48:07] [PASSED] 0x674D (CRESCENTISLAND)
[11:48:07] [PASSED] 0x674E (CRESCENTISLAND)
[11:48:07] [PASSED] 0x674F (CRESCENTISLAND)
[11:48:07] [PASSED] 0x6750 (CRESCENTISLAND)
[11:48:07] [PASSED] 0xD750 (NOVALAKE_P)
[11:48:07] [PASSED] 0xD751 (NOVALAKE_P)
[11:48:07] [PASSED] 0xD752 (NOVALAKE_P)
[11:48:07] [PASSED] 0xD753 (NOVALAKE_P)
[11:48:07] [PASSED] 0xD754 (NOVALAKE_P)
[11:48:07] [PASSED] 0xD755 (NOVALAKE_P)
[11:48:07] [PASSED] 0xD756 (NOVALAKE_P)
[11:48:07] [PASSED] 0xD757 (NOVALAKE_P)
[11:48:07] [PASSED] 0xD75F (NOVALAKE_P)
[11:48:07] =============== [PASSED] check_platform_desc ===============
[11:48:07] ===================== [PASSED] xe_pci ======================
[11:48:07] ============= xe_rtp_tables_test (5 subtests) ==============
[11:48:07] ================== xe_rtp_table_gt_test ===================
[11:48:07] [PASSED] gt_was/14011060649
[11:48:07] [PASSED] gt_was/14011059788
[11:48:07] [PASSED] gt_was/14015795083
[11:48:07] [PASSED] gt_was/16021867713
[11:48:07] [PASSED] gt_was/14019449301
[11:48:07] [PASSED] gt_was/16028005424
[11:48:07] [PASSED] gt_was/14026578760
[11:48:07] [PASSED] gt_was/1409420604
[11:48:07] [PASSED] gt_was/1408615072
[11:48:07] [PASSED] gt_was/22010523718
[11:48:07] [PASSED] gt_was/14011006942
[11:48:07] [PASSED] gt_was/14014830051
[11:48:07] [PASSED] gt_was/18018781329
[11:48:07] [PASSED] gt_was/1509235366
[11:48:07] [PASSED] gt_was/18018781329
[11:48:07] [PASSED] gt_was/16016694945
[11:48:07] [PASSED] gt_was/14018575942
[11:48:07] [PASSED] gt_was/22016670082
[11:48:07] [PASSED] gt_was/22016670082
[11:48:07] [PASSED] gt_was/14017421178
[11:48:07] [PASSED] gt_was/16025250150
[11:48:07] [PASSED] gt_was/14021871409
[11:48:07] [PASSED] gt_was/16021865536
[11:48:07] [PASSED] gt_was/14021486841
[11:48:07] [PASSED] gt_was/14025160223
[11:48:07] [PASSED] gt_was/14026144927, 16029437861, 14026127056
[11:48:07] [PASSED] gt_was/14025635424
[11:48:07] [PASSED] gt_was/16028005424
[11:48:07] ============== [PASSED] xe_rtp_table_gt_test ===============
[11:48:07] ================== xe_rtp_table_gt_test ===================
[11:48:07] [PASSED] gt_tunings/Tuning: Blend Fill Caching Optimization Disable
[11:48:07] [PASSED] gt_tunings/Tuning: 32B Access Enable
[11:48:07] [PASSED] gt_tunings/Tuning: L3 cache
[11:48:07] [PASSED] gt_tunings/Tuning: L3 cache - media
[11:48:07] [PASSED] gt_tunings/Tuning: Compression Overfetch
[11:48:07] [PASSED] gt_tunings/Tuning: Compression Overfetch - media
[11:48:07] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3
[11:48:07] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3 - media
[11:48:07] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only
[11:48:07] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only - media
[11:48:07] [PASSED] gt_tunings/Tuning: Stateless compression control
[11:48:07] [PASSED] gt_tunings/Tuning: Stateless compression control - media
[11:48:07] [PASSED] gt_tunings/Tuning: L3 RW flush all Cache
[11:48:07] [PASSED] gt_tunings/Tuning: L3 RW flush all cache - media
[11:48:07] [PASSED] gt_tunings/Tuning: Set STLB Bank Hash Mode to 4KB
[11:48:07] ============== [PASSED] xe_rtp_table_gt_test ===============
[11:48:07] ================== xe_rtp_table_oob_test ==================
[11:48:07] [PASSED] oob_was/1607983814
[11:48:07] [PASSED] oob_was/16010904313
[11:48:07] [PASSED] oob_was/18022495364
[11:48:07] [PASSED] oob_was/22012773006
[11:48:07] [PASSED] oob_was/14014475959
[11:48:07] [PASSED] oob_was/22011391025
[11:48:07] [PASSED] oob_was/22012727170
[11:48:07] [PASSED] oob_was/22012727685
[11:48:07] [PASSED] oob_was/22016596838
[11:48:07] [PASSED] oob_was/18020744125
[11:48:07] [PASSED] oob_was/1409600907
[11:48:07] [PASSED] oob_was/22014953428
[11:48:07] [PASSED] oob_was/16017236439
[11:48:07] [PASSED] oob_was/14019821291
[11:48:07] [PASSED] oob_was/14015076503
[11:48:07] [PASSED] oob_was/14018913170
[11:48:07] [PASSED] oob_was/14018094691
[11:48:07] [PASSED] oob_was/18024947630
[11:48:07] [PASSED] oob_was/16022287689
[11:48:07] [PASSED] oob_was/13011645652
[11:48:07] [PASSED] oob_was/14022293748
[11:48:07] [PASSED] oob_was/22019794406
[11:48:07] [PASSED] oob_was/22019338487
[11:48:07] [PASSED] oob_was/16023588340
[11:48:07] [PASSED] oob_was/14019789679
[11:48:07] [PASSED] oob_was/14022866841
[11:48:07] [PASSED] oob_was/16021333562
[11:48:07] [PASSED] oob_was/14016712196
[11:48:07] [PASSED] oob_was/14015568240
[11:48:07] [PASSED] oob_was/18013179988
[11:48:07] [PASSED] oob_was/1508761755
[11:48:07] [PASSED] oob_was/16023105232
[11:48:07] [PASSED] oob_was/16026508708
[11:48:07] [PASSED] oob_was/14020001231
[11:48:07] [PASSED] oob_was/16023683509
[11:48:07] [PASSED] oob_was/14025515070
[11:48:07] [PASSED] oob_was/15015404425_disable
[11:48:07] [PASSED] oob_was/16026007364
[11:48:07] [PASSED] oob_was/14020316580
[11:48:07] [PASSED] oob_was/14025883347
[11:48:07] [PASSED] oob_was/16029380221
[11:48:07] [PASSED] oob_was/22022079272
[11:48:07] [PASSED] oob_was/16029897822
[11:48:07] ============== [PASSED] xe_rtp_table_oob_test ==============
[11:48:07] ================ xe_rtp_table_dev_oob_test ================
[11:48:07] [PASSED] device_oob_was/22010954014
[11:48:07] [PASSED] device_oob_was/15015404425
[11:48:07] [PASSED] device_oob_was/22019338487_display
[11:48:07] [PASSED] device_oob_was/14022085890
[11:48:07] [PASSED] device_oob_was/14026539277
[11:48:07] [PASSED] device_oob_was/14026633728
[11:48:07] [PASSED] device_oob_was/14026746987
[11:48:07] [PASSED] device_oob_was/14026779378
[11:48:07] ============ [PASSED] xe_rtp_table_dev_oob_test ============
[11:48:07] ========== xe_rtp_table_missing_upper_bound_test ==========
[11:48:07] [PASSED] register_whitelist/WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865
[11:48:07] [PASSED] register_whitelist/1508744258, 14012131227, 1808121037
[11:48:07] [PASSED] register_whitelist/1806527549
[11:48:07] [PASSED] register_whitelist/allow_read_ctx_timestamp
[11:48:07] [PASSED] register_whitelist/allow_read_queue_timestamp
[11:48:07] [PASSED] register_whitelist/16014440446
[11:48:07] [PASSED] register_whitelist/16017236439
[11:48:07] [PASSED] register_whitelist/16020183090
[11:48:07] [PASSED] register_whitelist/14024997852
[11:48:07] [PASSED] register_whitelist/14024997852
[11:48:07] ====== [PASSED] xe_rtp_table_missing_upper_bound_test ======
[11:48:07] =============== [PASSED] xe_rtp_tables_test ================
[11:48:07] =================== xe_rtp (3 subtests) ====================
[11:48:07] =================== xe_rtp_rules_tests ====================
[11:48:07] [PASSED] no
[11:48:07] [PASSED] yes
[11:48:07] [PASSED] no-and-no
[11:48:07] [PASSED] no-and-yes
[11:48:07] [PASSED] yes-and-no
[11:48:07] [PASSED] yes-and-yes
[11:48:07] [PASSED] no-or-no
[11:48:07] [PASSED] no-or-yes
[11:48:07] [PASSED] yes-or-no
[11:48:07] [PASSED] yes-or-yes
[11:48:07] [PASSED] no-yes-or-yes-no
[11:48:07] [PASSED] no-yes-or-yes-yes
[11:48:07] [PASSED] yes-yes-or-no-yes
[11:48:07] [PASSED] yes-yes-or-yes-yes
[11:48:07] [PASSED] no-no-or-yes-or-no
[11:48:07] [PASSED] or
[11:48:07] [PASSED] or-yes
[11:48:07] [PASSED] or-no
[11:48:07] [PASSED] yes-or
[11:48:07] [PASSED] no-or
[11:48:07] [PASSED] no-or-or-yes
[11:48:07] [PASSED] yes-or-or-no
[11:48:07] [PASSED] no-or-or-no
[11:48:07] [PASSED] missing-context-engine-class
[11:48:07] [PASSED] missing-context-engine-class-or-yes
[11:48:07] [PASSED] missing-context-engine-class-or-or-yes
[11:48:07] =============== [PASSED] xe_rtp_rules_tests ================
[11:48:07] =============== xe_rtp_process_to_sr_tests ================
[11:48:07] [PASSED] coalesce-same-reg
[11:48:07] [PASSED] coalesce-same-reg-literal-and-func
[11:48:07] [PASSED] no-match-no-add
[11:48:07] [PASSED] two-regs-two-entries
[11:48:07] [PASSED] clr-one-set-other
[11:48:07] [PASSED] set-field
[11:48:07] [PASSED] conflict-duplicate
[11:48:07] [PASSED] conflict-not-disjoint
[11:48:07] [PASSED] conflict-not-disjoint-literal-and-func
[11:48:07] [PASSED] conflict-reg-type
[11:48:07] [PASSED] bad-mcr-reg-forced-to-regular
[11:48:07] [PASSED] bad-regular-reg-forced-to-mcr
[11:48:07] =========== [PASSED] xe_rtp_process_to_sr_tests ============
[11:48:07] ================== xe_rtp_process_tests ===================
[11:48:07] [PASSED] active1
[11:48:07] [PASSED] active2
[11:48:07] [PASSED] active-inactive
[11:48:07] [PASSED] inactive-active
[11:48:07] [PASSED] inactive-active-inactive
[11:48:07] [PASSED] inactive-inactive-inactive
[11:48:07] ============== [PASSED] xe_rtp_process_tests ===============
[11:48:07] ===================== [PASSED] xe_rtp ======================
[11:48:07] ==================== xe_wa (1 subtest) =====================
[11:48:07] ======================== xe_wa_gt =========================
[11:48:07] [PASSED] TIGERLAKE B0
[11:48:07] [PASSED] DG1 A0
[11:48:07] [PASSED] DG1 B0
[11:48:07] [PASSED] ALDERLAKE_S A0
[11:48:07] [PASSED] ALDERLAKE_S B0
[11:48:07] [PASSED] ALDERLAKE_S C0
[11:48:07] [PASSED] ALDERLAKE_S D0
[11:48:07] [PASSED] ALDERLAKE_P A0
[11:48:07] [PASSED] ALDERLAKE_P B0
[11:48:07] [PASSED] ALDERLAKE_P C0
[11:48:07] [PASSED] ALDERLAKE_S RPLS D0
[11:48:07] [PASSED] ALDERLAKE_P RPLU E0
[11:48:07] [PASSED] DG2 G10 C0
[11:48:07] [PASSED] DG2 G11 B1
[11:48:07] [PASSED] DG2 G12 A1
[11:48:07] [PASSED] METEORLAKE 12.70(Xe_LPG) A0 13.00(Xe_LPM+) A0
[11:48:07] [PASSED] METEORLAKE 12.71(Xe_LPG) A0 13.00(Xe_LPM+) A0
[11:48:07] [PASSED] METEORLAKE 12.74(Xe_LPG+) A0 13.00(Xe_LPM+) A0
[11:48:07] [PASSED] LUNARLAKE 20.04(Xe2_LPG) A0 20.00(Xe2_LPM) A0
[11:48:07] [PASSED] LUNARLAKE 20.04(Xe2_LPG) B0 20.00(Xe2_LPM) A0
[11:48:07] [PASSED] BATTLEMAGE 20.01(Xe2_HPG) A0 13.01(Xe2_HPM) A1
[11:48:07] [PASSED] PANTHERLAKE 30.00(Xe3_LPG) A0 30.00(Xe3_LPM) A0
[11:48:07] ==================== [PASSED] xe_wa_gt =====================
[11:48:07] ====================== [PASSED] xe_wa ======================
[11:48:07] ============================================================
[11:48:07] Testing complete. Ran 741 tests: passed: 723, skipped: 18
[11:48:07] Elapsed time: 37.345s total, 4.404s configuring, 32.275s building, 0.634s running
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/tests/.kunitconfig
[11:48:07] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[11:48:09] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[11:48:34] Starting KUnit Kernel (1/1)...
[11:48:34] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[11:48:34] ============ drm_test_pick_cmdline (2 subtests) ============
[11:48:34] [PASSED] drm_test_pick_cmdline_res_1920_1080_60
[11:48:34] =============== drm_test_pick_cmdline_named ===============
[11:48:34] [PASSED] NTSC
[11:48:34] [PASSED] NTSC-J
[11:48:34] [PASSED] PAL
[11:48:34] [PASSED] PAL-M
[11:48:34] =========== [PASSED] drm_test_pick_cmdline_named ===========
[11:48:34] ============== [PASSED] drm_test_pick_cmdline ==============
[11:48:34] == drm_test_atomic_get_connector_for_encoder (1 subtest) ===
[11:48:34] [PASSED] drm_test_drm_atomic_get_connector_for_encoder
[11:48:34] ==== [PASSED] drm_test_atomic_get_connector_for_encoder ====
[11:48:34] =========== drm_validate_clone_mode (2 subtests) ===========
[11:48:34] ============== drm_test_check_in_clone_mode ===============
[11:48:34] [PASSED] in_clone_mode
[11:48:34] [PASSED] not_in_clone_mode
[11:48:34] ========== [PASSED] drm_test_check_in_clone_mode ===========
[11:48:34] =============== drm_test_check_valid_clones ===============
[11:48:34] [PASSED] not_in_clone_mode
[11:48:34] [PASSED] valid_clone
[11:48:34] [PASSED] invalid_clone
[11:48:34] =========== [PASSED] drm_test_check_valid_clones ===========
[11:48:34] ============= [PASSED] drm_validate_clone_mode =============
[11:48:34] ============= drm_validate_modeset (1 subtest) =============
[11:48:34] [PASSED] drm_test_check_connector_changed_modeset
[11:48:34] ============== [PASSED] drm_validate_modeset ===============
[11:48:34] ====== drm_test_bridge_get_current_state (1 subtest) =======
[11:48:34] [PASSED] drm_test_drm_bridge_get_current_state_atomic
[11:48:34] ======== [PASSED] drm_test_bridge_get_current_state ========
[11:48:34] ====== drm_test_bridge_helper_reset_crtc (3 subtests) ======
[11:48:34] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic
[11:48:34] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic_disabled
[11:48:34] [PASSED] drm_test_drm_bridge_helper_hdmi_output_bus_fmts
[11:48:34] ======== [PASSED] drm_test_bridge_helper_reset_crtc ========
[11:48:34] ============== drm_bridge_alloc (2 subtests) ===============
[11:48:34] [PASSED] drm_test_drm_bridge_alloc_basic
[11:48:34] [PASSED] drm_test_drm_bridge_alloc_get_put
[11:48:34] ================ [PASSED] drm_bridge_alloc =================
[11:48:34] ============= drm_bridge_bus_fmt (5 subtests) ==============
[11:48:34] [PASSED] drm_test_bridge_rgb_yuv_rgb
[11:48:34] [PASSED] drm_test_bridge_must_convert_to_yuv444
[11:48:34] [PASSED] drm_test_bridge_hdmi_auto_rgb
[11:48:34] [PASSED] drm_test_bridge_auto_first
[11:48:34] [PASSED] drm_test_bridge_rgb_yuv_no_path
[11:48:34] =============== [PASSED] drm_bridge_bus_fmt ================
[11:48:34] ============= drm_cmdline_parser (40 subtests) =============
[11:48:34] [PASSED] drm_test_cmdline_force_d_only
[11:48:34] [PASSED] drm_test_cmdline_force_D_only_dvi
[11:48:34] [PASSED] drm_test_cmdline_force_D_only_hdmi
[11:48:34] [PASSED] drm_test_cmdline_force_D_only_not_digital
[11:48:34] [PASSED] drm_test_cmdline_force_e_only
[11:48:34] [PASSED] drm_test_cmdline_res
[11:48:34] [PASSED] drm_test_cmdline_res_vesa
[11:48:34] [PASSED] drm_test_cmdline_res_vesa_rblank
[11:48:34] [PASSED] drm_test_cmdline_res_rblank
[11:48:34] [PASSED] drm_test_cmdline_res_bpp
[11:48:34] [PASSED] drm_test_cmdline_res_refresh
[11:48:34] [PASSED] drm_test_cmdline_res_bpp_refresh
[11:48:34] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced
[11:48:34] [PASSED] drm_test_cmdline_res_bpp_refresh_margins
[11:48:34] [PASSED] drm_test_cmdline_res_bpp_refresh_force_off
[11:48:34] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on
[11:48:34] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_analog
[11:48:34] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_digital
[11:48:34] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced_margins_force_on
[11:48:34] [PASSED] drm_test_cmdline_res_margins_force_on
[11:48:34] [PASSED] drm_test_cmdline_res_vesa_margins
[11:48:34] [PASSED] drm_test_cmdline_name
[11:48:34] [PASSED] drm_test_cmdline_name_bpp
[11:48:34] [PASSED] drm_test_cmdline_name_option
[11:48:34] [PASSED] drm_test_cmdline_name_bpp_option
[11:48:34] [PASSED] drm_test_cmdline_rotate_0
[11:48:34] [PASSED] drm_test_cmdline_rotate_90
[11:48:34] [PASSED] drm_test_cmdline_rotate_180
[11:48:34] [PASSED] drm_test_cmdline_rotate_270
[11:48:34] [PASSED] drm_test_cmdline_hmirror
[11:48:34] [PASSED] drm_test_cmdline_vmirror
[11:48:34] [PASSED] drm_test_cmdline_margin_options
[11:48:34] [PASSED] drm_test_cmdline_multiple_options
[11:48:34] [PASSED] drm_test_cmdline_bpp_extra_and_option
[11:48:34] [PASSED] drm_test_cmdline_extra_and_option
[11:48:34] [PASSED] drm_test_cmdline_freestanding_options
[11:48:34] [PASSED] drm_test_cmdline_freestanding_force_e_and_options
[11:48:34] [PASSED] drm_test_cmdline_panel_orientation
[11:48:34] ================ drm_test_cmdline_invalid =================
[11:48:34] [PASSED] margin_only
[11:48:34] [PASSED] interlace_only
[11:48:34] [PASSED] res_missing_x
[11:48:34] [PASSED] res_missing_y
[11:48:34] [PASSED] res_bad_y
[11:48:34] [PASSED] res_missing_y_bpp
[11:48:34] [PASSED] res_bad_bpp
[11:48:34] [PASSED] res_bad_refresh
[11:48:34] [PASSED] res_bpp_refresh_force_on_off
[11:48:34] [PASSED] res_invalid_mode
[11:48:34] [PASSED] res_bpp_wrong_place_mode
[11:48:34] [PASSED] name_bpp_refresh
[11:48:34] [PASSED] name_refresh
[11:48:34] [PASSED] name_refresh_wrong_mode
[11:48:34] [PASSED] name_refresh_invalid_mode
[11:48:34] [PASSED] rotate_multiple
[11:48:34] [PASSED] rotate_invalid_val
[11:48:34] [PASSED] rotate_truncated
[11:48:34] [PASSED] invalid_option
[11:48:34] [PASSED] invalid_tv_option
[11:48:34] [PASSED] truncated_tv_option
[11:48:34] ============ [PASSED] drm_test_cmdline_invalid =============
[11:48:34] =============== drm_test_cmdline_tv_options ===============
[11:48:34] [PASSED] NTSC
[11:48:34] [PASSED] NTSC_443
[11:48:34] [PASSED] NTSC_J
[11:48:34] [PASSED] PAL
[11:48:34] [PASSED] PAL_M
[11:48:34] [PASSED] PAL_N
[11:48:34] [PASSED] SECAM
[11:48:34] [PASSED] MONO_525
[11:48:34] [PASSED] MONO_625
[11:48:34] =========== [PASSED] drm_test_cmdline_tv_options ===========
[11:48:34] =============== [PASSED] drm_cmdline_parser ================
[11:48:34] ========== drmm_connector_hdmi_init (20 subtests) ==========
[11:48:34] [PASSED] drm_test_connector_hdmi_init_valid
[11:48:34] [PASSED] drm_test_connector_hdmi_init_bpc_8
[11:48:34] [PASSED] drm_test_connector_hdmi_init_bpc_10
[11:48:34] [PASSED] drm_test_connector_hdmi_init_bpc_12
[11:48:34] [PASSED] drm_test_connector_hdmi_init_bpc_invalid
[11:48:34] [PASSED] drm_test_connector_hdmi_init_bpc_null
[11:48:34] [PASSED] drm_test_connector_hdmi_init_formats_empty
[11:48:34] [PASSED] drm_test_connector_hdmi_init_formats_no_rgb
[11:48:34] === drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[11:48:34] [PASSED] supported_formats=0x9 yuv420_allowed=1
[11:48:34] [PASSED] supported_formats=0x9 yuv420_allowed=0
[11:48:34] [PASSED] supported_formats=0x5 yuv420_allowed=1
[11:48:34] [PASSED] supported_formats=0x5 yuv420_allowed=0
[11:48:34] === [PASSED] drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[11:48:34] [PASSED] drm_test_connector_hdmi_init_null_ddc
[11:48:34] [PASSED] drm_test_connector_hdmi_init_null_product
[11:48:34] [PASSED] drm_test_connector_hdmi_init_null_vendor
[11:48:34] [PASSED] drm_test_connector_hdmi_init_product_length_exact
[11:48:34] [PASSED] drm_test_connector_hdmi_init_product_length_too_long
[11:48:34] [PASSED] drm_test_connector_hdmi_init_product_valid
[11:48:34] [PASSED] drm_test_connector_hdmi_init_vendor_length_exact
[11:48:34] [PASSED] drm_test_connector_hdmi_init_vendor_length_too_long
[11:48:34] [PASSED] drm_test_connector_hdmi_init_vendor_valid
[11:48:34] ========= drm_test_connector_hdmi_init_type_valid =========
[11:48:34] [PASSED] HDMI-A
[11:48:34] [PASSED] HDMI-B
[11:48:34] ===== [PASSED] drm_test_connector_hdmi_init_type_valid =====
[11:48:34] ======== drm_test_connector_hdmi_init_type_invalid ========
[11:48:34] [PASSED] Unknown
[11:48:34] [PASSED] VGA
[11:48:34] [PASSED] DVI-I
[11:48:34] [PASSED] DVI-D
[11:48:34] [PASSED] DVI-A
[11:48:34] [PASSED] Composite
[11:48:34] [PASSED] SVIDEO
[11:48:34] [PASSED] LVDS
[11:48:34] [PASSED] Component
[11:48:34] [PASSED] DIN
[11:48:34] [PASSED] DP
[11:48:34] [PASSED] TV
[11:48:34] [PASSED] eDP
[11:48:34] [PASSED] Virtual
[11:48:34] [PASSED] DSI
[11:48:34] [PASSED] DPI
[11:48:34] [PASSED] Writeback
[11:48:34] [PASSED] SPI
[11:48:34] [PASSED] USB
[11:48:34] ==== [PASSED] drm_test_connector_hdmi_init_type_invalid ====
[11:48:34] ============ [PASSED] drmm_connector_hdmi_init =============
[11:48:34] ============= drmm_connector_init (3 subtests) =============
[11:48:34] [PASSED] drm_test_drmm_connector_init
[11:48:34] [PASSED] drm_test_drmm_connector_init_null_ddc
[11:48:34] ========= drm_test_drmm_connector_init_type_valid =========
[11:48:34] [PASSED] Unknown
[11:48:34] [PASSED] VGA
[11:48:34] [PASSED] DVI-I
[11:48:34] [PASSED] DVI-D
[11:48:34] [PASSED] DVI-A
[11:48:34] [PASSED] Composite
[11:48:34] [PASSED] SVIDEO
[11:48:34] [PASSED] LVDS
[11:48:34] [PASSED] Component
[11:48:34] [PASSED] DIN
[11:48:34] [PASSED] DP
[11:48:34] [PASSED] HDMI-A
[11:48:34] [PASSED] HDMI-B
[11:48:34] [PASSED] TV
[11:48:34] [PASSED] eDP
[11:48:34] [PASSED] Virtual
[11:48:34] [PASSED] DSI
[11:48:34] [PASSED] DPI
[11:48:34] [PASSED] Writeback
[11:48:34] [PASSED] SPI
[11:48:34] [PASSED] USB
[11:48:34] ===== [PASSED] drm_test_drmm_connector_init_type_valid =====
[11:48:34] =============== [PASSED] drmm_connector_init ===============
[11:48:34] ========= drm_connector_dynamic_init (6 subtests) ==========
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_init
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_init_null_ddc
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_init_not_added
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_init_properties
[11:48:34] ===== drm_test_drm_connector_dynamic_init_type_valid ======
[11:48:34] [PASSED] Unknown
[11:48:34] [PASSED] VGA
[11:48:34] [PASSED] DVI-I
[11:48:34] [PASSED] DVI-D
[11:48:34] [PASSED] DVI-A
[11:48:34] [PASSED] Composite
[11:48:34] [PASSED] SVIDEO
[11:48:34] [PASSED] LVDS
[11:48:34] [PASSED] Component
[11:48:34] [PASSED] DIN
[11:48:34] [PASSED] DP
[11:48:34] [PASSED] HDMI-A
[11:48:34] [PASSED] HDMI-B
[11:48:34] [PASSED] TV
[11:48:34] [PASSED] eDP
[11:48:34] [PASSED] Virtual
[11:48:34] [PASSED] DSI
[11:48:34] [PASSED] DPI
[11:48:34] [PASSED] Writeback
[11:48:34] [PASSED] SPI
[11:48:34] [PASSED] USB
[11:48:34] = [PASSED] drm_test_drm_connector_dynamic_init_type_valid ==
[11:48:34] ======== drm_test_drm_connector_dynamic_init_name =========
[11:48:34] [PASSED] Unknown
[11:48:34] [PASSED] VGA
[11:48:34] [PASSED] DVI-I
[11:48:34] [PASSED] DVI-D
[11:48:34] [PASSED] DVI-A
[11:48:34] [PASSED] Composite
[11:48:34] [PASSED] SVIDEO
[11:48:34] [PASSED] LVDS
[11:48:34] [PASSED] Component
[11:48:34] [PASSED] DIN
[11:48:34] [PASSED] DP
[11:48:34] [PASSED] HDMI-A
[11:48:34] [PASSED] HDMI-B
[11:48:34] [PASSED] TV
[11:48:34] [PASSED] eDP
[11:48:34] [PASSED] Virtual
[11:48:34] [PASSED] DSI
[11:48:34] [PASSED] DPI
[11:48:34] [PASSED] Writeback
[11:48:34] [PASSED] SPI
[11:48:34] [PASSED] USB
[11:48:34] ==== [PASSED] drm_test_drm_connector_dynamic_init_name =====
[11:48:34] =========== [PASSED] drm_connector_dynamic_init ============
[11:48:34] ==== drm_connector_dynamic_register_early (4 subtests) =====
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_early_on_list
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_early_defer
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_early_no_init
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_early_no_mode_object
[11:48:34] ====== [PASSED] drm_connector_dynamic_register_early =======
[11:48:34] ======= drm_connector_dynamic_register (7 subtests) ========
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_on_list
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_no_defer
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_no_init
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_mode_object
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_sysfs
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_sysfs_name
[11:48:34] [PASSED] drm_test_drm_connector_dynamic_register_debugfs
[11:48:34] ========= [PASSED] drm_connector_dynamic_register ==========
[11:48:34] = drm_connector_attach_broadcast_rgb_property (2 subtests) =
[11:48:34] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property
[11:48:34] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector
[11:48:34] === [PASSED] drm_connector_attach_broadcast_rgb_property ===
[11:48:34] ========== drm_get_tv_mode_from_name (2 subtests) ==========
[11:48:34] ========== drm_test_get_tv_mode_from_name_valid ===========
[11:48:34] [PASSED] NTSC
[11:48:34] [PASSED] NTSC-443
[11:48:34] [PASSED] NTSC-J
[11:48:34] [PASSED] PAL
[11:48:34] [PASSED] PAL-M
[11:48:34] [PASSED] PAL-N
[11:48:34] [PASSED] SECAM
[11:48:34] [PASSED] Mono
[11:48:34] ====== [PASSED] drm_test_get_tv_mode_from_name_valid =======
[11:48:34] [PASSED] drm_test_get_tv_mode_from_name_truncated
[11:48:34] ============ [PASSED] drm_get_tv_mode_from_name ============
[11:48:34] = drm_test_connector_hdmi_compute_mode_clock (12 subtests) =
[11:48:34] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb
[11:48:34] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc
[11:48:34] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1
[11:48:34] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc
[11:48:34] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1
[11:48:34] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_double
[11:48:34] = drm_test_connector_hdmi_compute_mode_clock_yuv420_valid =
[11:48:34] [PASSED] VIC 96
[11:48:34] [PASSED] VIC 97
[11:48:34] [PASSED] VIC 101
[11:48:34] [PASSED] VIC 102
[11:48:34] [PASSED] VIC 106
[11:48:34] [PASSED] VIC 107
[11:48:34] === [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_valid ===
[11:48:34] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc
[11:48:34] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc
[11:48:34] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc
[11:48:34] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc
[11:48:34] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc
[11:48:34] === [PASSED] drm_test_connector_hdmi_compute_mode_clock ====
[11:48:34] == drm_hdmi_connector_get_broadcast_rgb_name (2 subtests) ==
[11:48:34] === drm_test_drm_hdmi_connector_get_broadcast_rgb_name ====
[11:48:34] [PASSED] Automatic
[11:48:34] [PASSED] Full
[11:48:34] [PASSED] Limited 16:235
[11:48:34] === [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name ===
[11:48:34] [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid
[11:48:34] ==== [PASSED] drm_hdmi_connector_get_broadcast_rgb_name ====
[11:48:34] == drm_hdmi_connector_get_output_format_name (2 subtests) ==
[11:48:34] === drm_test_drm_hdmi_connector_get_output_format_name ====
[11:48:34] [PASSED] RGB
[11:48:34] [PASSED] YUV 4:2:0
[11:48:34] [PASSED] YUV 4:2:2
[11:48:34] [PASSED] YUV 4:4:4
[11:48:34] === [PASSED] drm_test_drm_hdmi_connector_get_output_format_name ===
[11:48:34] [PASSED] drm_test_drm_hdmi_connector_get_output_format_name_invalid
[11:48:34] ==== [PASSED] drm_hdmi_connector_get_output_format_name ====
[11:48:34] ============= drm_damage_helper (21 subtests) ==============
[11:48:34] [PASSED] drm_test_damage_iter_no_damage
[11:48:34] [PASSED] drm_test_damage_iter_no_damage_fractional_src
[11:48:34] [PASSED] drm_test_damage_iter_no_damage_src_moved
[11:48:34] [PASSED] drm_test_damage_iter_no_damage_fractional_src_moved
[11:48:34] [PASSED] drm_test_damage_iter_no_damage_not_visible
[11:48:34] [PASSED] drm_test_damage_iter_no_damage_no_crtc
[11:48:34] [PASSED] drm_test_damage_iter_no_damage_no_fb
[11:48:34] [PASSED] drm_test_damage_iter_simple_damage
[11:48:34] [PASSED] drm_test_damage_iter_single_damage
[11:48:34] [PASSED] drm_test_damage_iter_single_damage_intersect_src
[11:48:34] [PASSED] drm_test_damage_iter_single_damage_outside_src
[11:48:34] [PASSED] drm_test_damage_iter_single_damage_fractional_src
[11:48:34] [PASSED] drm_test_damage_iter_single_damage_intersect_fractional_src
[11:48:34] [PASSED] drm_test_damage_iter_single_damage_outside_fractional_src
[11:48:34] [PASSED] drm_test_damage_iter_single_damage_src_moved
[11:48:34] [PASSED] drm_test_damage_iter_single_damage_fractional_src_moved
[11:48:34] [PASSED] drm_test_damage_iter_damage
[11:48:34] [PASSED] drm_test_damage_iter_damage_one_intersect
[11:48:34] [PASSED] drm_test_damage_iter_damage_one_outside
[11:48:34] [PASSED] drm_test_damage_iter_damage_src_moved
[11:48:34] [PASSED] drm_test_damage_iter_damage_not_visible
[11:48:34] ================ [PASSED] drm_damage_helper ================
[11:48:34] ============== drm_dp_mst_helper (3 subtests) ==============
[11:48:34] ============== drm_test_dp_mst_calc_pbn_mode ==============
[11:48:34] [PASSED] Clock 154000 BPP 30 DSC disabled
[11:48:34] [PASSED] Clock 234000 BPP 30 DSC disabled
[11:48:34] [PASSED] Clock 297000 BPP 24 DSC disabled
[11:48:34] [PASSED] Clock 332880 BPP 24 DSC enabled
[11:48:34] [PASSED] Clock 324540 BPP 24 DSC enabled
[11:48:34] ========== [PASSED] drm_test_dp_mst_calc_pbn_mode ==========
[11:48:34] ============== drm_test_dp_mst_calc_pbn_div ===============
[11:48:34] [PASSED] Link rate 2000000 lane count 4
[11:48:34] [PASSED] Link rate 2000000 lane count 2
[11:48:34] [PASSED] Link rate 2000000 lane count 1
[11:48:34] [PASSED] Link rate 1350000 lane count 4
[11:48:34] [PASSED] Link rate 1350000 lane count 2
[11:48:34] [PASSED] Link rate 1350000 lane count 1
[11:48:34] [PASSED] Link rate 1000000 lane count 4
[11:48:34] [PASSED] Link rate 1000000 lane count 2
[11:48:34] [PASSED] Link rate 1000000 lane count 1
[11:48:34] [PASSED] Link rate 810000 lane count 4
[11:48:34] [PASSED] Link rate 810000 lane count 2
[11:48:34] [PASSED] Link rate 810000 lane count 1
[11:48:34] [PASSED] Link rate 540000 lane count 4
[11:48:34] [PASSED] Link rate 540000 lane count 2
[11:48:34] [PASSED] Link rate 540000 lane count 1
[11:48:34] [PASSED] Link rate 270000 lane count 4
[11:48:34] [PASSED] Link rate 270000 lane count 2
[11:48:34] [PASSED] Link rate 270000 lane count 1
[11:48:34] [PASSED] Link rate 162000 lane count 4
[11:48:34] [PASSED] Link rate 162000 lane count 2
[11:48:34] [PASSED] Link rate 162000 lane count 1
[11:48:34] ========== [PASSED] drm_test_dp_mst_calc_pbn_div ===========
[11:48:34] ========= drm_test_dp_mst_sideband_msg_req_decode =========
[11:48:34] [PASSED] DP_ENUM_PATH_RESOURCES with port number
[11:48:34] [PASSED] DP_POWER_UP_PHY with port number
[11:48:34] [PASSED] DP_POWER_DOWN_PHY with port number
[11:48:34] [PASSED] DP_ALLOCATE_PAYLOAD with SDP stream sinks
[11:48:34] [PASSED] DP_ALLOCATE_PAYLOAD with port number
[11:48:34] [PASSED] DP_ALLOCATE_PAYLOAD with VCPI
[11:48:34] [PASSED] DP_ALLOCATE_PAYLOAD with PBN
[11:48:34] [PASSED] DP_QUERY_PAYLOAD with port number
[11:48:34] [PASSED] DP_QUERY_PAYLOAD with VCPI
[11:48:34] [PASSED] DP_REMOTE_DPCD_READ with port number
[11:48:34] [PASSED] DP_REMOTE_DPCD_READ with DPCD address
[11:48:34] [PASSED] DP_REMOTE_DPCD_READ with max number of bytes
[11:48:34] [PASSED] DP_REMOTE_DPCD_WRITE with port number
[11:48:34] [PASSED] DP_REMOTE_DPCD_WRITE with DPCD address
[11:48:34] [PASSED] DP_REMOTE_DPCD_WRITE with data array
[11:48:34] [PASSED] DP_REMOTE_I2C_READ with port number
[11:48:34] [PASSED] DP_REMOTE_I2C_READ with I2C device ID
[11:48:34] [PASSED] DP_REMOTE_I2C_READ with transactions array
[11:48:34] [PASSED] DP_REMOTE_I2C_WRITE with port number
[11:48:34] [PASSED] DP_REMOTE_I2C_WRITE with I2C device ID
[11:48:34] [PASSED] DP_REMOTE_I2C_WRITE with data array
[11:48:34] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream ID
[11:48:34] [PASSED] DP_QUERY_STREAM_ENC_STATUS with client ID
[11:48:34] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream event
[11:48:34] [PASSED] DP_QUERY_STREAM_ENC_STATUS with valid stream event
[11:48:34] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream behavior
[11:48:34] [PASSED] DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior
[11:48:34] ===== [PASSED] drm_test_dp_mst_sideband_msg_req_decode =====
[11:48:34] ================ [PASSED] drm_dp_mst_helper ================
[11:48:34] ================== drm_exec (7 subtests) ===================
[11:48:34] [PASSED] sanitycheck
[11:48:34] [PASSED] test_lock
[11:48:34] [PASSED] test_lock_unlock
[11:48:34] [PASSED] test_duplicates
[11:48:34] [PASSED] test_prepare
[11:48:34] [PASSED] test_prepare_array
[11:48:34] [PASSED] test_multiple_loops
[11:48:34] ==================== [PASSED] drm_exec =====================
[11:48:34] =========== drm_format_helper_test (17 subtests) ===========
[11:48:34] ============== drm_test_fb_xrgb8888_to_gray8 ==============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ========== [PASSED] drm_test_fb_xrgb8888_to_gray8 ==========
[11:48:34] ============= drm_test_fb_xrgb8888_to_rgb332 ==============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb332 ==========
[11:48:34] ============= drm_test_fb_xrgb8888_to_rgb565 ==============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb565 ==========
[11:48:34] ============ drm_test_fb_xrgb8888_to_xrgb1555 =============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ======== [PASSED] drm_test_fb_xrgb8888_to_xrgb1555 =========
[11:48:34] ============ drm_test_fb_xrgb8888_to_argb1555 =============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ======== [PASSED] drm_test_fb_xrgb8888_to_argb1555 =========
[11:48:34] ============ drm_test_fb_xrgb8888_to_rgba5551 =============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ======== [PASSED] drm_test_fb_xrgb8888_to_rgba5551 =========
[11:48:34] ============= drm_test_fb_xrgb8888_to_rgb888 ==============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb888 ==========
[11:48:34] ============= drm_test_fb_xrgb8888_to_bgr888 ==============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ========= [PASSED] drm_test_fb_xrgb8888_to_bgr888 ==========
[11:48:34] ============ drm_test_fb_xrgb8888_to_argb8888 =============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ======== [PASSED] drm_test_fb_xrgb8888_to_argb8888 =========
[11:48:34] =========== drm_test_fb_xrgb8888_to_xrgb2101010 ===========
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ======= [PASSED] drm_test_fb_xrgb8888_to_xrgb2101010 =======
[11:48:34] =========== drm_test_fb_xrgb8888_to_argb2101010 ===========
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ======= [PASSED] drm_test_fb_xrgb8888_to_argb2101010 =======
[11:48:34] ============== drm_test_fb_xrgb8888_to_mono ===============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ========== [PASSED] drm_test_fb_xrgb8888_to_mono ===========
[11:48:34] ==================== drm_test_fb_swab =====================
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ================ [PASSED] drm_test_fb_swab =================
[11:48:34] ============ drm_test_fb_xrgb8888_to_xbgr8888 =============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ======== [PASSED] drm_test_fb_xrgb8888_to_xbgr8888 =========
[11:48:34] ============ drm_test_fb_xrgb8888_to_abgr8888 =============
[11:48:34] [PASSED] single_pixel_source_buffer
[11:48:34] [PASSED] single_pixel_clip_rectangle
[11:48:34] [PASSED] well_known_colors
[11:48:34] [PASSED] destination_pitch
[11:48:34] ======== [PASSED] drm_test_fb_xrgb8888_to_abgr8888 =========
[11:48:34] ================= drm_test_fb_clip_offset =================
[11:48:34] [PASSED] pass through
[11:48:34] [PASSED] horizontal offset
[11:48:34] [PASSED] vertical offset
[11:48:34] [PASSED] horizontal and vertical offset
[11:48:34] [PASSED] horizontal offset (custom pitch)
[11:48:34] [PASSED] vertical offset (custom pitch)
[11:48:34] [PASSED] horizontal and vertical offset (custom pitch)
[11:48:34] ============= [PASSED] drm_test_fb_clip_offset =============
[11:48:34] =================== drm_test_fb_memcpy ====================
[11:48:34] [PASSED] single_pixel_source_buffer: XR24 little-endian (0x34325258)
[11:48:34] [PASSED] single_pixel_source_buffer: XRA8 little-endian (0x38415258)
[11:48:34] [PASSED] single_pixel_source_buffer: YU24 little-endian (0x34325559)
[11:48:34] [PASSED] single_pixel_clip_rectangle: XB24 little-endian (0x34324258)
[11:48:34] [PASSED] single_pixel_clip_rectangle: XRA8 little-endian (0x38415258)
[11:48:34] [PASSED] single_pixel_clip_rectangle: YU24 little-endian (0x34325559)
[11:48:34] [PASSED] well_known_colors: XB24 little-endian (0x34324258)
[11:48:34] [PASSED] well_known_colors: XRA8 little-endian (0x38415258)
[11:48:34] [PASSED] well_known_colors: YU24 little-endian (0x34325559)
[11:48:34] [PASSED] destination_pitch: XB24 little-endian (0x34324258)
[11:48:34] [PASSED] destination_pitch: XRA8 little-endian (0x38415258)
[11:48:34] [PASSED] destination_pitch: YU24 little-endian (0x34325559)
[11:48:34] =============== [PASSED] drm_test_fb_memcpy ================
[11:48:34] ============= [PASSED] drm_format_helper_test ==============
[11:48:34] ================= drm_format (18 subtests) =================
[11:48:34] [PASSED] drm_test_format_block_width_invalid
[11:48:34] [PASSED] drm_test_format_block_width_one_plane
[11:48:34] [PASSED] drm_test_format_block_width_two_plane
[11:48:34] [PASSED] drm_test_format_block_width_three_plane
[11:48:34] [PASSED] drm_test_format_block_width_tiled
[11:48:34] [PASSED] drm_test_format_block_height_invalid
[11:48:34] [PASSED] drm_test_format_block_height_one_plane
[11:48:34] [PASSED] drm_test_format_block_height_two_plane
[11:48:34] [PASSED] drm_test_format_block_height_three_plane
[11:48:34] [PASSED] drm_test_format_block_height_tiled
[11:48:34] [PASSED] drm_test_format_min_pitch_invalid
[11:48:34] [PASSED] drm_test_format_min_pitch_one_plane_8bpp
[11:48:34] [PASSED] drm_test_format_min_pitch_one_plane_16bpp
[11:48:34] [PASSED] drm_test_format_min_pitch_one_plane_24bpp
[11:48:34] [PASSED] drm_test_format_min_pitch_one_plane_32bpp
[11:48:34] [PASSED] drm_test_format_min_pitch_two_plane
[11:48:34] [PASSED] drm_test_format_min_pitch_three_plane_8bpp
[11:48:34] [PASSED] drm_test_format_min_pitch_tiled
[11:48:34] =================== [PASSED] drm_format ====================
[11:48:34] ============== drm_framebuffer (10 subtests) ===============
[11:48:34] ========== drm_test_framebuffer_check_src_coords ==========
[11:48:34] [PASSED] Success: source fits into fb
[11:48:34] [PASSED] Fail: overflowing fb with x-axis coordinate
[11:48:34] [PASSED] Fail: overflowing fb with y-axis coordinate
[11:48:34] [PASSED] Fail: overflowing fb with source width
[11:48:34] [PASSED] Fail: overflowing fb with source height
[11:48:34] ====== [PASSED] drm_test_framebuffer_check_src_coords ======
[11:48:34] [PASSED] drm_test_framebuffer_cleanup
[11:48:34] =============== drm_test_framebuffer_create ===============
[11:48:34] [PASSED] ABGR8888 normal sizes
[11:48:34] [PASSED] ABGR8888 max sizes
[11:48:34] [PASSED] ABGR8888 pitch greater than min required
[11:48:34] [PASSED] ABGR8888 pitch less than min required
[11:48:34] [PASSED] ABGR8888 Invalid width
[11:48:34] [PASSED] ABGR8888 Invalid buffer handle
[11:48:34] [PASSED] No pixel format
[11:48:34] [PASSED] ABGR8888 Width 0
[11:48:34] [PASSED] ABGR8888 Height 0
[11:48:34] [PASSED] ABGR8888 Out of bound height * pitch combination
[11:48:34] [PASSED] ABGR8888 Large buffer offset
[11:48:34] [PASSED] ABGR8888 Buffer offset for inexistent plane
[11:48:34] [PASSED] ABGR8888 Invalid flag
[11:48:34] [PASSED] ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers
[11:48:34] [PASSED] ABGR8888 Valid buffer modifier
[11:48:34] [PASSED] ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
[11:48:34] [PASSED] ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS
[11:48:34] [PASSED] ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS
[11:48:34] [PASSED] NV12 Normal sizes
[11:48:34] [PASSED] NV12 Max sizes
[11:48:34] [PASSED] NV12 Invalid pitch
[11:48:34] [PASSED] NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag
[11:48:34] [PASSED] NV12 different modifier per-plane
[11:48:34] [PASSED] NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
[11:48:34] [PASSED] NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS
[11:48:34] [PASSED] NV12 Modifier for inexistent plane
[11:48:34] [PASSED] NV12 Handle for inexistent plane
[11:48:34] [PASSED] NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS
[11:48:34] [PASSED] YVU420 DRM_MODE_FB_MODIFIERS set without modifier
[11:48:34] [PASSED] YVU420 Normal sizes
[11:48:34] [PASSED] YVU420 Max sizes
[11:48:34] [PASSED] YVU420 Invalid pitch
[11:48:34] [PASSED] YVU420 Different pitches
[11:48:34] [PASSED] YVU420 Different buffer offsets/pitches
[11:48:34] [PASSED] YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS
[11:48:34] [PASSED] YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS
[11:48:34] [PASSED] YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS
[11:48:34] [PASSED] YVU420 Valid modifier
[11:48:34] [PASSED] YVU420 Different modifiers per plane
[11:48:34] [PASSED] YVU420 Modifier for inexistent plane
[11:48:34] [PASSED] YUV420_10BIT Invalid modifier(DRM_FORMAT_MOD_LINEAR)
[11:48:34] [PASSED] X0L2 Normal sizes
[11:48:34] [PASSED] X0L2 Max sizes
[11:48:34] [PASSED] X0L2 Invalid pitch
[11:48:34] [PASSED] X0L2 Pitch greater than minimum required
[11:48:34] [PASSED] X0L2 Handle for inexistent plane
[11:48:34] [PASSED] X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set
[11:48:34] [PASSED] X0L2 Modifier without DRM_MODE_FB_MODIFIERS set
[11:48:34] [PASSED] X0L2 Valid modifier
[11:48:34] [PASSED] X0L2 Modifier for inexistent plane
[11:48:34] =========== [PASSED] drm_test_framebuffer_create ===========
[11:48:34] [PASSED] drm_test_framebuffer_free
[11:48:34] [PASSED] drm_test_framebuffer_init
[11:48:34] [PASSED] drm_test_framebuffer_init_bad_format
[11:48:34] [PASSED] drm_test_framebuffer_init_dev_mismatch
[11:48:34] [PASSED] drm_test_framebuffer_lookup
[11:48:34] [PASSED] drm_test_framebuffer_lookup_inexistent
[11:48:34] [PASSED] drm_test_framebuffer_modifiers_not_supported
[11:48:34] ================= [PASSED] drm_framebuffer =================
[11:48:34] ================ drm_gem_shmem (8 subtests) ================
[11:48:34] [PASSED] drm_gem_shmem_test_obj_create
[11:48:34] [PASSED] drm_gem_shmem_test_obj_create_private
[11:48:34] [PASSED] drm_gem_shmem_test_pin_pages
[11:48:34] [PASSED] drm_gem_shmem_test_vmap
[11:48:34] [PASSED] drm_gem_shmem_test_get_sg_table
[11:48:34] [PASSED] drm_gem_shmem_test_get_pages_sgt
[11:48:34] [PASSED] drm_gem_shmem_test_madvise
[11:48:34] [PASSED] drm_gem_shmem_test_purge
[11:48:34] ================== [PASSED] drm_gem_shmem ==================
[11:48:34] === drm_atomic_helper_connector_hdmi_check (29 subtests) ===
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode_vic_1
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode_vic_1
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode_vic_1
[11:48:34] ====== drm_test_check_broadcast_rgb_cea_mode_yuv420 =======
[11:48:34] [PASSED] Automatic
[11:48:34] [PASSED] Full
[11:48:34] [PASSED] Limited 16:235
[11:48:34] == [PASSED] drm_test_check_broadcast_rgb_cea_mode_yuv420 ===
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_changed
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_not_changed
[11:48:34] [PASSED] drm_test_check_disable_connector
[11:48:34] [PASSED] drm_test_check_hdmi_funcs_reject_rate
[11:48:34] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_rgb
[11:48:34] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_yuv420
[11:48:34] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422
[11:48:34] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420
[11:48:34] [PASSED] drm_test_check_driver_unsupported_fallback_yuv420
[11:48:34] [PASSED] drm_test_check_output_bpc_crtc_mode_changed
[11:48:34] [PASSED] drm_test_check_output_bpc_crtc_mode_not_changed
[11:48:34] [PASSED] drm_test_check_output_bpc_dvi
[11:48:34] [PASSED] drm_test_check_output_bpc_format_vic_1
[11:48:34] [PASSED] drm_test_check_output_bpc_format_display_8bpc_only
[11:48:34] [PASSED] drm_test_check_output_bpc_format_display_rgb_only
[11:48:34] [PASSED] drm_test_check_output_bpc_format_driver_8bpc_only
[11:48:34] [PASSED] drm_test_check_output_bpc_format_driver_rgb_only
[11:48:34] [PASSED] drm_test_check_tmds_char_rate_rgb_8bpc
[11:48:34] [PASSED] drm_test_check_tmds_char_rate_rgb_10bpc
[11:48:34] [PASSED] drm_test_check_tmds_char_rate_rgb_12bpc
[11:48:34] ============ drm_test_check_hdmi_color_format =============
[11:48:34] [PASSED] AUTO -> RGB
[11:48:34] [PASSED] YCBCR422 -> YUV422
[11:48:34] [PASSED] YCBCR420 -> YUV420
[11:48:34] [PASSED] YCBCR444 -> YUV444
[11:48:34] [PASSED] RGB -> RGB
[11:48:34] ======== [PASSED] drm_test_check_hdmi_color_format =========
[11:48:34] ======== drm_test_check_hdmi_color_format_420_only ========
[11:48:34] [PASSED] RGB should fail
[11:48:34] [PASSED] YUV444 should fail
[11:48:34] [PASSED] YUV422 should fail
[11:48:34] [PASSED] YUV420 should work
[11:48:34] ==== [PASSED] drm_test_check_hdmi_color_format_420_only ====
[11:48:34] ===== [PASSED] drm_atomic_helper_connector_hdmi_check ======
[11:48:34] === drm_atomic_helper_connector_hdmi_reset (6 subtests) ====
[11:48:34] [PASSED] drm_test_check_broadcast_rgb_value
[11:48:34] [PASSED] drm_test_check_bpc_8_value
[11:48:34] [PASSED] drm_test_check_bpc_10_value
[11:48:34] [PASSED] drm_test_check_bpc_12_value
[11:48:34] [PASSED] drm_test_check_format_value
[11:48:34] [PASSED] drm_test_check_tmds_char_value
[11:48:34] ===== [PASSED] drm_atomic_helper_connector_hdmi_reset ======
[11:48:34] = drm_atomic_helper_connector_hdmi_mode_valid (7 subtests) =
[11:48:34] [PASSED] drm_test_check_mode_valid
[11:48:34] [PASSED] drm_test_check_mode_valid_reject
[11:48:34] [PASSED] drm_test_check_mode_valid_reject_rate
[11:48:34] [PASSED] drm_test_check_mode_valid_reject_max_clock
[11:48:34] [PASSED] drm_test_check_mode_valid_yuv420_only_max_clock
[11:48:34] [PASSED] drm_test_check_mode_valid_reject_yuv420_only_connector
[11:48:34] [PASSED] drm_test_check_mode_valid_accept_yuv420_also_connector_rgb
[11:48:34] === [PASSED] drm_atomic_helper_connector_hdmi_mode_valid ===
[11:48:34] = drm_atomic_helper_connector_hdmi_infoframes (5 subtests) =
[11:48:34] [PASSED] drm_test_check_infoframes
[11:48:34] [PASSED] drm_test_check_reject_avi_infoframe
[11:48:34] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_8
[11:48:34] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_10
[11:48:34] [PASSED] drm_test_check_reject_audio_infoframe
[11:48:34] === [PASSED] drm_atomic_helper_connector_hdmi_infoframes ===
[11:48:34] ================= drm_managed (2 subtests) =================
[11:48:34] [PASSED] drm_test_managed_release_action
[11:48:34] [PASSED] drm_test_managed_run_action
[11:48:34] =================== [PASSED] drm_managed ===================
[11:48:34] =================== drm_mm (6 subtests) ====================
[11:48:34] [PASSED] drm_test_mm_init
[11:48:34] [PASSED] drm_test_mm_debug
[11:48:34] [PASSED] drm_test_mm_align32
[11:48:34] [PASSED] drm_test_mm_align64
[11:48:34] [PASSED] drm_test_mm_lowest
[11:48:34] [PASSED] drm_test_mm_highest
[11:48:34] ===================== [PASSED] drm_mm ======================
[11:48:34] ============= drm_modes_analog_tv (5 subtests) =============
[11:48:34] [PASSED] drm_test_modes_analog_tv_mono_576i
[11:48:34] [PASSED] drm_test_modes_analog_tv_ntsc_480i
[11:48:34] [PASSED] drm_test_modes_analog_tv_ntsc_480i_inlined
[11:48:34] [PASSED] drm_test_modes_analog_tv_pal_576i
[11:48:34] [PASSED] drm_test_modes_analog_tv_pal_576i_inlined
[11:48:34] =============== [PASSED] drm_modes_analog_tv ===============
[11:48:34] ============== drm_plane_helper (2 subtests) ===============
[11:48:34] =============== drm_test_check_plane_state ================
[11:48:34] [PASSED] clipping_simple
[11:48:34] [PASSED] clipping_rotate_reflect
[11:48:34] [PASSED] positioning_simple
[11:48:34] [PASSED] upscaling
[11:48:34] [PASSED] downscaling
[11:48:34] [PASSED] rounding1
[11:48:34] [PASSED] rounding2
[11:48:34] [PASSED] rounding3
[11:48:34] [PASSED] rounding4
[11:48:34] =========== [PASSED] drm_test_check_plane_state ============
[11:48:34] =========== drm_test_check_invalid_plane_state ============
[11:48:34] [PASSED] positioning_invalid
[11:48:34] [PASSED] upscaling_invalid
[11:48:34] [PASSED] downscaling_invalid
[11:48:34] ======= [PASSED] drm_test_check_invalid_plane_state ========
[11:48:34] ================ [PASSED] drm_plane_helper =================
[11:48:34] ====== drm_connector_helper_tv_get_modes (1 subtest) =======
[11:48:34] ====== drm_test_connector_helper_tv_get_modes_check =======
[11:48:34] [PASSED] None
[11:48:34] [PASSED] PAL
[11:48:34] [PASSED] NTSC
[11:48:34] [PASSED] Both, NTSC Default
[11:48:34] [PASSED] Both, PAL Default
[11:48:34] [PASSED] Both, NTSC Default, with PAL on command-line
[11:48:34] [PASSED] Both, PAL Default, with NTSC on command-line
[11:48:34] == [PASSED] drm_test_connector_helper_tv_get_modes_check ===
[11:48:34] ======== [PASSED] drm_connector_helper_tv_get_modes ========
[11:48:34] ================== drm_rect (9 subtests) ===================
[11:48:34] [PASSED] drm_test_rect_clip_scaled_div_by_zero
[11:48:34] [PASSED] drm_test_rect_clip_scaled_not_clipped
[11:48:34] [PASSED] drm_test_rect_clip_scaled_clipped
[11:48:34] [PASSED] drm_test_rect_clip_scaled_signed_vs_unsigned
[11:48:34] ================= drm_test_rect_intersect =================
[11:48:34] [PASSED] top-left x bottom-right: 2x2+1+1 x 2x2+0+0
[11:48:34] [PASSED] top-right x bottom-left: 2x2+0+0 x 2x2+1-1
[11:48:34] [PASSED] bottom-left x top-right: 2x2+1-1 x 2x2+0+0
[11:48:34] [PASSED] bottom-right x top-left: 2x2+0+0 x 2x2+1+1
[11:48:34] [PASSED] right x left: 2x1+0+0 x 3x1+1+0
[11:48:34] [PASSED] left x right: 3x1+1+0 x 2x1+0+0
[11:48:34] [PASSED] up x bottom: 1x2+0+0 x 1x3+0-1
[11:48:34] [PASSED] bottom x up: 1x3+0-1 x 1x2+0+0
[11:48:34] [PASSED] touching corner: 1x1+0+0 x 2x2+1+1
[11:48:34] [PASSED] touching side: 1x1+0+0 x 1x1+1+0
[11:48:34] [PASSED] equal rects: 2x2+0+0 x 2x2+0+0
[11:48:34] [PASSED] inside another: 2x2+0+0 x 1x1+1+1
[11:48:34] [PASSED] far away: 1x1+0+0 x 1x1+3+6
[11:48:34] [PASSED] points intersecting: 0x0+5+10 x 0x0+5+10
[11:48:34] [PASSED] points not intersecting: 0x0+0+0 x 0x0+5+10
[11:48:34] ============= [PASSED] drm_test_rect_intersect =============
[11:48:34] ================ drm_test_rect_calc_hscale ================
[11:48:34] [PASSED] normal use
[11:48:34] [PASSED] out of max range
[11:48:34] [PASSED] out of min range
[11:48:34] [PASSED] zero dst
[11:48:34] [PASSED] negative src
[11:48:34] [PASSED] negative dst
[11:48:34] ============ [PASSED] drm_test_rect_calc_hscale ============
[11:48:34] ================ drm_test_rect_calc_vscale ================
[11:48:34] [PASSED] normal use
[11:48:34] [PASSED] out of max range
[11:48:34] [PASSED] out of min range
[11:48:34] [PASSED] zero dst
[11:48:34] [PASSED] negative src
[11:48:34] [PASSED] negative dst
[11:48:34] ============ [PASSED] drm_test_rect_calc_vscale ============
[11:48:34] ================== drm_test_rect_rotate ===================
[11:48:34] [PASSED] reflect-x
[11:48:34] [PASSED] reflect-y
[11:48:34] [PASSED] rotate-0
[11:48:34] [PASSED] rotate-90
[11:48:34] [PASSED] rotate-180
[11:48:34] [PASSED] rotate-270
[11:48:34] ============== [PASSED] drm_test_rect_rotate ===============
[11:48:34] ================ drm_test_rect_rotate_inv =================
[11:48:34] [PASSED] reflect-x
[11:48:34] [PASSED] reflect-y
[11:48:34] [PASSED] rotate-0
[11:48:34] [PASSED] rotate-90
[11:48:34] [PASSED] rotate-180
[11:48:34] [PASSED] rotate-270
[11:48:34] ============ [PASSED] drm_test_rect_rotate_inv =============
[11:48:34] ==================== [PASSED] drm_rect =====================
[11:48:34] ============ drm_sysfb_modeset_test (1 subtest) ============
[11:48:34] ============ drm_test_sysfb_build_fourcc_list =============
[11:48:34] [PASSED] no native formats
[11:48:34] [PASSED] XRGB8888 as native format
[11:48:34] [PASSED] remove duplicates
[11:48:34] [PASSED] convert alpha formats
[11:48:34] [PASSED] random formats
[11:48:34] ======== [PASSED] drm_test_sysfb_build_fourcc_list =========
[11:48:34] ============= [PASSED] drm_sysfb_modeset_test ==============
[11:48:34] ================== drm_fixp (2 subtests) ===================
[11:48:34] [PASSED] drm_test_int2fixp
[11:48:34] [PASSED] drm_test_sm2fixp
[11:48:34] ==================== [PASSED] drm_fixp =====================
[11:48:34] ============================================================
[11:48:34] Testing complete. Ran 637 tests: passed: 637
[11:48:34] Elapsed time: 27.138s total, 1.741s configuring, 25.228s building, 0.145s running
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig
[11:48:34] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[11:48:36] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[11:48:46] Starting KUnit Kernel (1/1)...
[11:48:46] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[11:48:46] ================= ttm_device (5 subtests) ==================
[11:48:46] [PASSED] ttm_device_init_basic
[11:48:46] [PASSED] ttm_device_init_multiple
[11:48:46] [PASSED] ttm_device_fini_basic
[11:48:46] [PASSED] ttm_device_init_no_vma_man
[11:48:46] ================== ttm_device_init_pools ==================
[11:48:46] [PASSED] No DMA allocations, no DMA32 required
[11:48:46] [PASSED] DMA allocations, DMA32 required
[11:48:46] [PASSED] No DMA allocations, DMA32 required
[11:48:46] [PASSED] DMA allocations, no DMA32 required
[11:48:46] ============== [PASSED] ttm_device_init_pools ==============
[11:48:46] =================== [PASSED] ttm_device ====================
[11:48:46] ================== ttm_pool (8 subtests) ===================
[11:48:46] ================== ttm_pool_alloc_basic ===================
[11:48:46] [PASSED] One page
[11:48:46] [PASSED] More than one page
[11:48:46] [PASSED] Above the allocation limit
[11:48:46] [PASSED] One page, with coherent DMA mappings enabled
[11:48:46] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[11:48:46] ============== [PASSED] ttm_pool_alloc_basic ===============
[11:48:46] ============== ttm_pool_alloc_basic_dma_addr ==============
[11:48:46] [PASSED] One page
[11:48:46] [PASSED] More than one page
[11:48:46] [PASSED] Above the allocation limit
[11:48:46] [PASSED] One page, with coherent DMA mappings enabled
[11:48:46] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[11:48:46] ========== [PASSED] ttm_pool_alloc_basic_dma_addr ==========
[11:48:46] [PASSED] ttm_pool_alloc_order_caching_match
[11:48:46] [PASSED] ttm_pool_alloc_caching_mismatch
[11:48:46] [PASSED] ttm_pool_alloc_order_mismatch
[11:48:46] [PASSED] ttm_pool_free_dma_alloc
[11:48:46] [PASSED] ttm_pool_free_no_dma_alloc
[11:48:46] [PASSED] ttm_pool_fini_basic
[11:48:46] ==================== [PASSED] ttm_pool =====================
[11:48:46] ================ ttm_resource (8 subtests) =================
[11:48:46] ================= ttm_resource_init_basic =================
[11:48:46] [PASSED] Init resource in TTM_PL_SYSTEM
[11:48:46] [PASSED] Init resource in TTM_PL_VRAM
[11:48:46] [PASSED] Init resource in a private placement
[11:48:46] [PASSED] Init resource in TTM_PL_SYSTEM, set placement flags
[11:48:46] ============= [PASSED] ttm_resource_init_basic =============
[11:48:46] [PASSED] ttm_resource_init_pinned
[11:48:46] [PASSED] ttm_resource_fini_basic
[11:48:46] [PASSED] ttm_resource_manager_init_basic
[11:48:46] [PASSED] ttm_resource_manager_usage_basic
[11:48:46] [PASSED] ttm_resource_manager_set_used_basic
[11:48:46] [PASSED] ttm_sys_man_alloc_basic
[11:48:46] [PASSED] ttm_sys_man_free_basic
[11:48:46] ================== [PASSED] ttm_resource ===================
[11:48:46] =================== ttm_tt (15 subtests) ===================
[11:48:46] ==================== ttm_tt_init_basic ====================
[11:48:46] [PASSED] Page-aligned size
[11:48:46] [PASSED] Extra pages requested
[11:48:46] ================ [PASSED] ttm_tt_init_basic ================
[11:48:46] [PASSED] ttm_tt_init_misaligned
[11:48:46] [PASSED] ttm_tt_fini_basic
[11:48:46] [PASSED] ttm_tt_fini_sg
[11:48:46] [PASSED] ttm_tt_fini_shmem
[11:48:46] [PASSED] ttm_tt_create_basic
[11:48:46] [PASSED] ttm_tt_create_invalid_bo_type
[11:48:46] [PASSED] ttm_tt_create_ttm_exists
[11:48:46] [PASSED] ttm_tt_create_failed
[11:48:46] [PASSED] ttm_tt_destroy_basic
[11:48:46] [PASSED] ttm_tt_populate_null_ttm
[11:48:46] [PASSED] ttm_tt_populate_populated_ttm
[11:48:46] [PASSED] ttm_tt_unpopulate_basic
[11:48:46] [PASSED] ttm_tt_unpopulate_empty_ttm
[11:48:46] [PASSED] ttm_tt_swapin_basic
[11:48:46] ===================== [PASSED] ttm_tt ======================
[11:48:46] =================== ttm_bo (14 subtests) ===================
[11:48:46] =========== ttm_bo_reserve_optimistic_no_ticket ===========
[11:48:46] [PASSED] Cannot be interrupted and sleeps
[11:48:46] [PASSED] Cannot be interrupted, locks straight away
[11:48:46] [PASSED] Can be interrupted, sleeps
[11:48:46] ======= [PASSED] ttm_bo_reserve_optimistic_no_ticket =======
[11:48:46] [PASSED] ttm_bo_reserve_locked_no_sleep
[11:48:46] [PASSED] ttm_bo_reserve_no_wait_ticket
[11:48:46] [PASSED] ttm_bo_reserve_double_resv
[11:48:46] [PASSED] ttm_bo_reserve_interrupted
[11:48:46] [PASSED] ttm_bo_reserve_deadlock
[11:48:46] [PASSED] ttm_bo_unreserve_basic
[11:48:46] [PASSED] ttm_bo_unreserve_pinned
[11:48:46] [PASSED] ttm_bo_unreserve_bulk
[11:48:46] [PASSED] ttm_bo_fini_basic
[11:48:46] [PASSED] ttm_bo_fini_shared_resv
[11:48:46] [PASSED] ttm_bo_pin_basic
[11:48:46] [PASSED] ttm_bo_pin_unpin_resource
[11:48:46] [PASSED] ttm_bo_multiple_pin_one_unpin
[11:48:46] ===================== [PASSED] ttm_bo ======================
[11:48:46] ============== ttm_bo_validate (22 subtests) ===============
[11:48:46] ============== ttm_bo_init_reserved_sys_man ===============
[11:48:46] [PASSED] Buffer object for userspace
[11:48:46] [PASSED] Kernel buffer object
[11:48:46] [PASSED] Shared buffer object
[11:48:46] ========== [PASSED] ttm_bo_init_reserved_sys_man ===========
[11:48:46] ============== ttm_bo_init_reserved_mock_man ==============
[11:48:46] [PASSED] Buffer object for userspace
[11:48:46] [PASSED] Kernel buffer object
[11:48:46] [PASSED] Shared buffer object
[11:48:46] ========== [PASSED] ttm_bo_init_reserved_mock_man ==========
[11:48:46] [PASSED] ttm_bo_init_reserved_resv
[11:48:46] ================== ttm_bo_validate_basic ==================
[11:48:46] [PASSED] Buffer object for userspace
[11:48:46] [PASSED] Kernel buffer object
[11:48:46] [PASSED] Shared buffer object
[11:48:46] ============== [PASSED] ttm_bo_validate_basic ==============
[11:48:46] [PASSED] ttm_bo_validate_invalid_placement
[11:48:46] ============= ttm_bo_validate_same_placement ==============
[11:48:46] [PASSED] System manager
[11:48:46] [PASSED] VRAM manager
[11:48:46] ========= [PASSED] ttm_bo_validate_same_placement ==========
[11:48:46] [PASSED] ttm_bo_validate_failed_alloc
[11:48:46] [PASSED] ttm_bo_validate_pinned
[11:48:46] [PASSED] ttm_bo_validate_busy_placement
[11:48:46] ================ ttm_bo_validate_multihop =================
[11:48:46] [PASSED] Buffer object for userspace
[11:48:46] [PASSED] Kernel buffer object
[11:48:46] [PASSED] Shared buffer object
[11:48:46] ============ [PASSED] ttm_bo_validate_multihop =============
[11:48:46] ========== ttm_bo_validate_no_placement_signaled ==========
[11:48:46] [PASSED] Buffer object in system domain, no page vector
[11:48:46] [PASSED] Buffer object in system domain with an existing page vector
[11:48:46] ====== [PASSED] ttm_bo_validate_no_placement_signaled ======
[11:48:46] ======== ttm_bo_validate_no_placement_not_signaled ========
[11:48:46] [PASSED] Buffer object for userspace
[11:48:46] [PASSED] Kernel buffer object
[11:48:46] [PASSED] Shared buffer object
[11:48:46] ==== [PASSED] ttm_bo_validate_no_placement_not_signaled ====
[11:48:46] [PASSED] ttm_bo_validate_move_fence_signaled
[11:48:46] ========= ttm_bo_validate_move_fence_not_signaled =========
[11:48:46] [PASSED] Waits for GPU
[11:48:46] [PASSED] Tries to lock straight away
[11:48:46] ===== [PASSED] ttm_bo_validate_move_fence_not_signaled =====
[11:48:46] [PASSED] ttm_bo_validate_swapout
[11:48:46] [PASSED] ttm_bo_validate_happy_evict
[11:48:46] [PASSED] ttm_bo_validate_all_pinned_evict
[11:48:46] [PASSED] ttm_bo_validate_allowed_only_evict
[11:48:46] [PASSED] ttm_bo_validate_deleted_evict
[11:48:46] [PASSED] ttm_bo_validate_busy_domain_evict
[11:48:46] [PASSED] ttm_bo_validate_evict_gutting
[11:48:46] [PASSED] ttm_bo_validate_recrusive_evict
[11:48:46] ================= [PASSED] ttm_bo_validate =================
[11:48:46] ============================================================
[11:48:46] Testing complete. Ran 102 tests: passed: 102
[11:48:46] Elapsed time: 12.029s total, 1.814s configuring, 9.950s building, 0.228s running
+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller
2026-07-23 10:03 ` [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller Thomas Hellström
2026-07-23 10:31 ` sashiko-bot
@ 2026-07-23 12:02 ` Maarten Lankhorst
2026-07-23 15:55 ` Thomas Hellström
1 sibling, 1 reply; 16+ messages in thread
From: Maarten Lankhorst @ 2026-07-23 12:02 UTC (permalink / raw)
To: Thomas Hellström, intel-xe
Cc: Natalie Vock, Johannes Weiner, Tejun Heo, Michal Koutný,
cgroups, Huang Rui, Matthew Brost, Matthew Auld, Maxime Ripard,
Thomas Zimmermann, Simona Vetter, David Airlie,
Christian König, Thadeu Lima de Souza Cascardo, Alex Deucher,
Rodrigo Vivi, dri-devel, amd-gfx, linux-kernel
Hey,
On 7/23/26 12:03, Thomas Hellström wrote:
> Add ttm_bo_evict_cgroup() to evict buffer objects charged to a specific
> dmem cgroup pool from a resource manager's LRU until a byte target is
> met. Add ttm_resource_manager_set_dmem_region() to associate a dmem
> cgroup region with a resource manager; drivers supply their own
> dmem_cgroup_ops with ttm_resource_manager_dmem_reclaim as the reclaim
> function and the manager pointer as reclaim_priv in the dmem_cgroup_init
> to wire up TTM eviction as the reclaim callback.
>
> The eviction context is interruptible; signals abort the operation and
> propagate back through the write() syscall.
>
> Introduce a new mode for the bo LRU walker so that sleeping locks
> can be taken. This can be used when the caller doesn't hold any
> previous dma_resv locks, and where it intends to hold at most
> one lock at a time.
>
> Like the rest of the TTM eviction this should sooner than later
> be converted to full WW transactions.
>
> v3:
> - Fix ttm_resource_manager_set_dmem_region() storing an error pointer
> in man->cg unconditionally. (Sashiko-bot)
> - Fix kernel-doc function name format for ttm_bo_evict_cgroup() and
> ttm_resource_manager_set_dmem_region().
>
> v5:
> - Rebased on the introduction of struct dmem_cgroup_init.
> - Handle NULL region in ttm_resource_manager_set_dmem_region() to clear
> the reclaim callback, preventing use-after-free when the manager is
> torn down while the dmem region outlives it. (Sashiko-bot)
> - Return 0 on any progress (even partial eviction), -ENOSPC only when
> nothing was freed; fixes callers that expected 0 on partial success.
> - Document that the reclaim callback should return 0 if some progress
> was made, -ENOSPC if no progress at all, or another error for fatal
> failures.
>
> v8:
> - Fix ttm_resource_manager_set_dmem_region() using IS_ERR_OR_NULL(),
> which skipped the assignment for a NULL region and thus never
> cleared man->cg. Use IS_ERR() so that a NULL region detaches the
> region as the kernel-doc and the v5 changelog intended. (Sashiko-bot)
>
> Assisted-by: GitHub_Copilot:claude-sonnet-4.6
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> #v7
> ---
> drivers/gpu/drm/ttm/ttm_bo.c | 95 +++++++++++++++++++++++++++++-
> drivers/gpu/drm/ttm/ttm_bo_util.c | 3 +-
> drivers/gpu/drm/ttm/ttm_resource.c | 52 ++++++++++++++++
> include/drm/ttm/ttm_bo.h | 10 ++++
> include/drm/ttm/ttm_resource.h | 7 +++
> 5 files changed, 163 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 3980f376e3ba..b2bbbb69add3 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -515,12 +515,20 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
> {
> struct ttm_bo_evict_walk *evict_walk =
> container_of(walk, typeof(*evict_walk), walk);
> + /* Capture size before eviction in case res is cleared. */
> + s64 bo_size = bo->base.size;
I just noticed this comment, a bo's size should be fixed, even if the backing store is gone?
> s64 lret;
>
> if (!dmem_cgroup_state_evict_valuable(evict_walk->limit_pool, bo->resource->css,
> evict_walk->try_low, &evict_walk->hit_low))
> return 0;
>
> + /*
> + * evict_walk->place is NULL in cgroup drain mode. Drivers'
> + * eviction_valuable() callbacks must handle a NULL place, treating it
> + * as "any placement": the TTM base implementation already does so via
> + * ttm_resource_intersects().
> + */
> if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place))
> return 0;
>
> @@ -536,11 +544,15 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
> goto out;
>
> evict_walk->evicted++;
> - if (evict_walk->res)
> + if (evict_walk->res) {
> lret = ttm_resource_alloc(evict_walk->evictor, evict_walk->place,
> evict_walk->res, NULL);
> - if (lret == 0)
> - return 1;
> + if (lret == 0)
> + return 1;
> + } else {
> + /* Cgroup drain: return bytes freed for byte-denominated progress. */
> + return bo_size;
> + }
> out:
> /* Errors that should terminate the walk. */
> if (lret == -ENOSPC)
> @@ -614,6 +626,83 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
> return 0;
> }
>
> +/**
> + * ttm_bo_evict_cgroup() - Evict buffer objects charged to a specific cgroup.
> + * @bdev: The TTM device.
> + * @man: The resource manager whose LRU to walk.
> + * @limit_pool: The cgroup pool state whose members should be evicted.
> + * @target_bytes: Number of bytes to free.
> + * @ctx: The TTM operation context.
> + *
> + * Walk the LRU of @man and evict buffer objects that are charged to the
> + * cgroup identified by @limit_pool, until at least @target_bytes have been
> + * freed. Mirrors the two-pass (trylock -> sleeping-lock, low-watermark)
> + * strategy used by ttm_bo_evict_alloc().
> + *
> + * Return: >= @target_bytes on full success, 0..target_bytes-1 if partial,
> + * negative error code on fatal error.
> + */
> +s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
> + struct ttm_resource_manager *man,
> + struct dmem_cgroup_pool_state *limit_pool,
> + s64 target_bytes,
> + struct ttm_operation_ctx *ctx)
> +{
> + struct ttm_bo_evict_walk evict_walk = {
> + .walk = {
> + .ops = &ttm_evict_walk_ops,
> + .arg = { .ctx = ctx },
> + },
> + .limit_pool = limit_pool,
> + /* place, evictor, res left NULL: selects cgroup drain mode */
> + };
> + s64 lret, pass;
> +
> + evict_walk.walk.arg.trylock_only = true;
> + lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, target_bytes);
> + if (lret < 0 || lret >= target_bytes)
> + return lret;
> +
> + /* Second pass: also evict BOs at the low watermark. */
> + if (evict_walk.hit_low) {
> + evict_walk.try_low = true;
> + pass = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
> + target_bytes - lret);
> + if (pass < 0)
> + return pass;
> + lret += pass;
> + if (lret >= target_bytes)
> + return lret;
> + }
> +
> + /* Full sleeping-lock pass for remaining target. */
> + evict_walk.try_low = evict_walk.hit_low = false;
> + evict_walk.walk.arg.trylock_only = false;
> +
> +retry:
> + evict_walk.walk.arg.sleeping_lock = true;
> + do {
> + evict_walk.evicted = 0;
> + pass = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
> + target_bytes - lret);
> + if (pass < 0) {
> + lret = pass;
> + goto out;
> + }
> + lret += pass;
> + } while (lret < target_bytes && evict_walk.evicted);
> +
> + /* One more attempt if we hit the low limit during sleeping-lock pass. */
> + if (lret < target_bytes && evict_walk.hit_low && !evict_walk.try_low) {
> + evict_walk.try_low = true;
> + goto retry;
> + }
> +
> +out:
> + return lret;
> +}
> +EXPORT_SYMBOL(ttm_bo_evict_cgroup);
> +
> /**
> * ttm_bo_pin - Pin the buffer object.
> * @bo: The buffer object to pin
> diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
> index 3e3c201a0222..bd0b23ac2cc4 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo_util.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
> @@ -999,7 +999,8 @@ __ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
> bo = res->bo;
> if (ttm_lru_walk_trylock(curs, bo))
> bo_locked = true;
> - else if (!arg->ticket || arg->ctx->no_wait_gpu || arg->trylock_only)
> + else if ((!arg->ticket && !arg->sleeping_lock) || arg->ctx->no_wait_gpu ||
> + arg->trylock_only)
> continue;
>
> if (!ttm_bo_get_unless_zero(bo)) {
> diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
> index 154d6739256f..1ff4a470b083 100644
> --- a/drivers/gpu/drm/ttm/ttm_resource.c
> +++ b/drivers/gpu/drm/ttm/ttm_resource.c
> @@ -953,3 +953,55 @@ void ttm_resource_manager_create_debugfs(struct ttm_resource_manager *man,
> #endif
> }
> EXPORT_SYMBOL(ttm_resource_manager_create_debugfs);
> +
> +/**
> + * ttm_resource_manager_dmem_reclaim() - dmem cgroup reclaim callback for TTM
> + * resource managers.
> + * @pool: The dmem cgroup pool state for the cgroup being reclaimed.
> + * @target_bytes: Number of bytes to try to free.
> + * @priv: The &ttm_resource_manager pointer, passed as @init.reclaim_priv to
> + * dmem_cgroup_register_region().
> + *
> + * Drivers should use this as the @reclaim member of their own
> + * &struct dmem_cgroup_ops, with the &ttm_resource_manager pointer as
> + * @init.reclaim_priv.
> + *
> + * Return: 0 if some memory was freed, -ENOSPC if nothing was freed, or
> + * another negative error code on fatal failure.
> + */
> +int ttm_resource_manager_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
> + u64 target_bytes, void *priv)
> +{
> + struct ttm_resource_manager *man = priv;
> + struct ttm_operation_ctx ctx = { .interruptible = true };
> + s64 freed;
> +
> + freed = ttm_bo_evict_cgroup(man->bdev, man, pool, target_bytes, &ctx);
> + if (freed < 0)
> + return freed;
> +
> + return freed > 0 ? 0 : -ENOSPC;
> +}
> +EXPORT_SYMBOL(ttm_resource_manager_dmem_reclaim);
> +
> +/**
> + * ttm_resource_manager_set_dmem_region() - Associate a dmem cgroup region with a
> + * resource manager.
> + * @man: The resource manager.
> + * @region: The dmem cgroup region to associate, may be NULL or IS_ERR().
> + *
> + * When @region is valid, stores it in @man->cg so that TTM can look up the
> + * associated pool during charging and eviction-target selection. When
> + * @region is %NULL, clears @man->cg to detach the region before teardown.
> + * An IS_ERR() @region is ignored, leaving @man->cg unchanged.
> + * The reclaim callback must be wired up using ttm_resource_manager_dmem_reclaim()
> + * in the driver's own &struct dmem_cgroup_ops, with the manager pointer as
> + * @init.reclaim_priv.
> + */
> +void ttm_resource_manager_set_dmem_region(struct ttm_resource_manager *man,
> + struct dmem_cgroup_region *region)
> +{
> + if (!IS_ERR(region))
> + man->cg = region;
> +}
> +EXPORT_SYMBOL(ttm_resource_manager_set_dmem_region);
> diff --git a/include/drm/ttm/ttm_bo.h b/include/drm/ttm/ttm_bo.h
> index 8310bc3d55f9..32791c4db2a9 100644
> --- a/include/drm/ttm/ttm_bo.h
> +++ b/include/drm/ttm/ttm_bo.h
> @@ -226,6 +226,11 @@ struct ttm_lru_walk_arg {
> struct ww_acquire_ctx *ticket;
> /** @trylock_only: Only use trylock for locking. */
> bool trylock_only;
> + /**
> + * @sleeping_lock: Use sleeping locks even with %NULL @ticket.
> + * @trylock_only has precedence over this field.
> + */
> + bool sleeping_lock;
> };
>
> /**
> @@ -431,6 +436,11 @@ void ttm_bo_unpin(struct ttm_buffer_object *bo);
> int ttm_bo_evict_first(struct ttm_device *bdev,
> struct ttm_resource_manager *man,
> struct ttm_operation_ctx *ctx);
> +s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
> + struct ttm_resource_manager *man,
> + struct dmem_cgroup_pool_state *limit_pool,
> + s64 target_bytes,
> + struct ttm_operation_ctx *ctx);
> int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset,
> void *buf, int len, int write);
> vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
> diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h
> index a5d386583fb6..32e485fdce9a 100644
> --- a/include/drm/ttm/ttm_resource.h
> +++ b/include/drm/ttm/ttm_resource.h
> @@ -39,6 +39,7 @@
>
> struct dentry;
> struct dmem_cgroup_device;
> +struct dmem_cgroup_region;
> struct drm_printer;
> struct ttm_device;
> struct ttm_resource_manager;
> @@ -477,6 +478,12 @@ void ttm_resource_manager_init(struct ttm_resource_manager *man,
> struct ttm_device *bdev,
> uint64_t size);
>
> +void ttm_resource_manager_set_dmem_region(struct ttm_resource_manager *man,
> + struct dmem_cgroup_region *region);
> +
> +int ttm_resource_manager_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
> + u64 target_bytes, void *priv);
> +
> int ttm_resource_manager_evict_all(struct ttm_device *bdev,
> struct ttm_resource_manager *man);
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* ✓ Xe.CI.BAT: success for Add reclaim to the dmem cgroup controller (rev8)
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
` (7 preceding siblings ...)
2026-07-23 11:48 ` ✓ CI.KUnit: success " Patchwork
@ 2026-07-23 12:29 ` Patchwork
8 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2026-07-23 12:29 UTC (permalink / raw)
To: Thomas Hellström; +Cc: intel-xe
[-- Attachment #1: Type: text/plain, Size: 4841 bytes --]
== Series Details ==
Series: Add reclaim to the dmem cgroup controller (rev8)
URL : https://patchwork.freedesktop.org/series/163970/
State : success
== Summary ==
CI Bug Log - changes from xe-5467-2c64192f1ad194a53800f6dd8c779d5b4bbc1831_BAT -> xe-pw-163970v8_BAT
====================================================
Summary
-------
**SUCCESS**
No regressions found.
Participating hosts (12 -> 13)
------------------------------
Additional (1): bat-bmg-2
Known issues
------------
Here are the changes found in xe-pw-163970v8_BAT that come from known issues:
### IGT changes ###
#### Issues hit ####
* igt@fbdev@write:
- bat-bmg-2: NOTRUN -> [SKIP][1] ([Intel XE#2134]) +4 other tests skip
[1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@fbdev@write.html
* igt@kms_addfb_basic@addfb25-y-tiled-small-legacy:
- bat-bmg-2: NOTRUN -> [SKIP][2] ([Intel XE#2233])
[2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@kms_addfb_basic@addfb25-y-tiled-small-legacy.html
* igt@kms_cursor_legacy@basic-flip-after-cursor-legacy:
- bat-bmg-2: NOTRUN -> [SKIP][3] ([Intel XE#2489] / [Intel XE#3419]) +13 other tests skip
[3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@kms_cursor_legacy@basic-flip-after-cursor-legacy.html
* igt@kms_flip@basic-flip-vs-modeset:
- bat-bmg-2: NOTRUN -> [SKIP][4] ([Intel XE#2482]) +3 other tests skip
[4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@kms_flip@basic-flip-vs-modeset.html
* igt@kms_frontbuffer_tracking@basic:
- bat-bmg-2: NOTRUN -> [SKIP][5] ([Intel XE#2434] / [Intel XE#2548] / [Intel XE#6314])
[5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@kms_frontbuffer_tracking@basic.html
* igt@kms_psr@psr-sprite-plane-onoff:
- bat-bmg-2: NOTRUN -> [SKIP][6] ([Intel XE#2234] / [Intel XE#2850]) +2 other tests skip
[6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@kms_psr@psr-sprite-plane-onoff.html
* igt@xe_exec_multi_queue@priority:
- bat-bmg-2: NOTRUN -> [SKIP][7] ([Intel XE#8364]) +13 other tests skip
[7]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@xe_exec_multi_queue@priority.html
* igt@xe_live_ktest@xe_bo@xe_ccs_migrate_kunit:
- bat-bmg-2: NOTRUN -> [SKIP][8] ([Intel XE#2229])
[8]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@xe_live_ktest@xe_bo@xe_ccs_migrate_kunit.html
* igt@xe_pat@pat-index-xehpc:
- bat-bmg-2: NOTRUN -> [SKIP][9] ([Intel XE#1420] / [Intel XE#7590])
[9]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@xe_pat@pat-index-xehpc.html
* igt@xe_pat@pat-index-xelp:
- bat-bmg-2: NOTRUN -> [SKIP][10] ([Intel XE#2245] / [Intel XE#7590])
[10]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@xe_pat@pat-index-xelp.html
* igt@xe_pat@pat-index-xelpg:
- bat-bmg-2: NOTRUN -> [SKIP][11] ([Intel XE#2236] / [Intel XE#7590])
[11]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/bat-bmg-2/igt@xe_pat@pat-index-xelpg.html
[Intel XE#1420]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1420
[Intel XE#2134]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2134
[Intel XE#2229]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2229
[Intel XE#2233]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2233
[Intel XE#2234]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2234
[Intel XE#2236]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2236
[Intel XE#2245]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2245
[Intel XE#2434]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2434
[Intel XE#2482]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2482
[Intel XE#2489]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2489
[Intel XE#2548]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2548
[Intel XE#2850]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2850
[Intel XE#3419]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3419
[Intel XE#6314]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6314
[Intel XE#7590]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7590
[Intel XE#8364]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8364
Build changes
-------------
* Linux: xe-5467-2c64192f1ad194a53800f6dd8c779d5b4bbc1831 -> xe-pw-163970v8
IGT_9020: 9020
xe-5467-2c64192f1ad194a53800f6dd8c779d5b4bbc1831: 2c64192f1ad194a53800f6dd8c779d5b4bbc1831
xe-pw-163970v8: 163970v8
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-163970v8/index.html
[-- Attachment #2: Type: text/html, Size: 5753 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller
2026-07-23 12:02 ` Maarten Lankhorst
@ 2026-07-23 15:55 ` Thomas Hellström
0 siblings, 0 replies; 16+ messages in thread
From: Thomas Hellström @ 2026-07-23 15:55 UTC (permalink / raw)
To: Maarten Lankhorst, intel-xe
Cc: Natalie Vock, Johannes Weiner, Tejun Heo, Michal Koutný,
cgroups, Huang Rui, Matthew Brost, Matthew Auld, Maxime Ripard,
Thomas Zimmermann, Simona Vetter, David Airlie,
Christian König, Thadeu Lima de Souza Cascardo, Alex Deucher,
Rodrigo Vivi, dri-devel, amd-gfx, linux-kernel
On Thu, 2026-07-23 at 14:02 +0200, Maarten Lankhorst wrote:
> Hey,
>
> On 7/23/26 12:03, Thomas Hellström wrote:
> > Add ttm_bo_evict_cgroup() to evict buffer objects charged to a
> > specific
> > dmem cgroup pool from a resource manager's LRU until a byte target
> > is
> > met. Add ttm_resource_manager_set_dmem_region() to associate a
> > dmem
> > cgroup region with a resource manager; drivers supply their own
> > dmem_cgroup_ops with ttm_resource_manager_dmem_reclaim as the
> > reclaim
> > function and the manager pointer as reclaim_priv in the
> > dmem_cgroup_init
> > to wire up TTM eviction as the reclaim callback.
> >
> > The eviction context is interruptible; signals abort the operation
> > and
> > propagate back through the write() syscall.
> >
> > Introduce a new mode for the bo LRU walker so that sleeping locks
> > can be taken. This can be used when the caller doesn't hold any
> > previous dma_resv locks, and where it intends to hold at most
> > one lock at a time.
> >
> > Like the rest of the TTM eviction this should sooner than later
> > be converted to full WW transactions.
> >
> > v3:
> > - Fix ttm_resource_manager_set_dmem_region() storing an error
> > pointer
> > in man->cg unconditionally. (Sashiko-bot)
> > - Fix kernel-doc function name format for ttm_bo_evict_cgroup() and
> > ttm_resource_manager_set_dmem_region().
> >
> > v5:
> > - Rebased on the introduction of struct dmem_cgroup_init.
> > - Handle NULL region in ttm_resource_manager_set_dmem_region() to
> > clear
> > the reclaim callback, preventing use-after-free when the manager
> > is
> > torn down while the dmem region outlives it. (Sashiko-bot)
> > - Return 0 on any progress (even partial eviction), -ENOSPC only
> > when
> > nothing was freed; fixes callers that expected 0 on partial
> > success.
> > - Document that the reclaim callback should return 0 if some
> > progress
> > was made, -ENOSPC if no progress at all, or another error for
> > fatal
> > failures.
> >
> > v8:
> > - Fix ttm_resource_manager_set_dmem_region() using
> > IS_ERR_OR_NULL(),
> > which skipped the assignment for a NULL region and thus never
> > cleared man->cg. Use IS_ERR() so that a NULL region detaches the
> > region as the kernel-doc and the v5 changelog intended. (Sashiko-
> > bot)
> >
> > Assisted-by: GitHub_Copilot:claude-sonnet-4.6
> > Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> > Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > #v7
> > ---
> > drivers/gpu/drm/ttm/ttm_bo.c | 95
> > +++++++++++++++++++++++++++++-
> > drivers/gpu/drm/ttm/ttm_bo_util.c | 3 +-
> > drivers/gpu/drm/ttm/ttm_resource.c | 52 ++++++++++++++++
> > include/drm/ttm/ttm_bo.h | 10 ++++
> > include/drm/ttm/ttm_resource.h | 7 +++
> > 5 files changed, 163 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/ttm/ttm_bo.c
> > b/drivers/gpu/drm/ttm/ttm_bo.c
> > index 3980f376e3ba..b2bbbb69add3 100644
> > --- a/drivers/gpu/drm/ttm/ttm_bo.c
> > +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> > @@ -515,12 +515,20 @@ static s64 ttm_bo_evict_cb(struct
> > ttm_lru_walk *walk, struct ttm_buffer_object *
> > {
> > struct ttm_bo_evict_walk *evict_walk =
> > container_of(walk, typeof(*evict_walk), walk);
> > + /* Capture size before eviction in case res is cleared. */
> > + s64 bo_size = bo->base.size;
>
> I just noticed this comment, a bo's size should be fixed, even if the
> backing store is gone?
Yeah, correct. Looks like an old leftover. I'll remove.
I'll post a v9 as well, since initialization seems a bit tricky to get
right.
Thanks,
Thomas
>
> > s64 lret;
> >
> > if (!dmem_cgroup_state_evict_valuable(evict_walk-
> > >limit_pool, bo->resource->css,
> > evict_walk->try_low,
> > &evict_walk->hit_low))
> > return 0;
> >
> > + /*
> > + * evict_walk->place is NULL in cgroup drain mode.
> > Drivers'
> > + * eviction_valuable() callbacks must handle a NULL place,
> > treating it
> > + * as "any placement": the TTM base implementation already
> > does so via
> > + * ttm_resource_intersects().
> > + */
> > if (bo->pin_count || !bo->bdev->funcs-
> > >eviction_valuable(bo, evict_walk->place))
> > return 0;
> >
> > @@ -536,11 +544,15 @@ static s64 ttm_bo_evict_cb(struct
> > ttm_lru_walk *walk, struct ttm_buffer_object *
> > goto out;
> >
> > evict_walk->evicted++;
> > - if (evict_walk->res)
> > + if (evict_walk->res) {
> > lret = ttm_resource_alloc(evict_walk->evictor,
> > evict_walk->place,
> > evict_walk->res, NULL);
> > - if (lret == 0)
> > - return 1;
> > + if (lret == 0)
> > + return 1;
> > + } else {
> > + /* Cgroup drain: return bytes freed for byte-
> > denominated progress. */
> > + return bo_size;
> > + }
> > out:
> > /* Errors that should terminate the walk. */
> > if (lret == -ENOSPC)
> > @@ -614,6 +626,83 @@ static int ttm_bo_evict_alloc(struct
> > ttm_device *bdev,
> > return 0;
> > }
> >
> > +/**
> > + * ttm_bo_evict_cgroup() - Evict buffer objects charged to a
> > specific cgroup.
> > + * @bdev: The TTM device.
> > + * @man: The resource manager whose LRU to walk.
> > + * @limit_pool: The cgroup pool state whose members should be
> > evicted.
> > + * @target_bytes: Number of bytes to free.
> > + * @ctx: The TTM operation context.
> > + *
> > + * Walk the LRU of @man and evict buffer objects that are charged
> > to the
> > + * cgroup identified by @limit_pool, until at least @target_bytes
> > have been
> > + * freed. Mirrors the two-pass (trylock -> sleeping-lock, low-
> > watermark)
> > + * strategy used by ttm_bo_evict_alloc().
> > + *
> > + * Return: >= @target_bytes on full success, 0..target_bytes-1 if
> > partial,
> > + * negative error code on fatal error.
> > + */
> > +s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
> > + struct ttm_resource_manager *man,
> > + struct dmem_cgroup_pool_state *limit_pool,
> > + s64 target_bytes,
> > + struct ttm_operation_ctx *ctx)
> > +{
> > + struct ttm_bo_evict_walk evict_walk = {
> > + .walk = {
> > + .ops = &ttm_evict_walk_ops,
> > + .arg = { .ctx = ctx },
> > + },
> > + .limit_pool = limit_pool,
> > + /* place, evictor, res left NULL: selects cgroup
> > drain mode */
> > + };
> > + s64 lret, pass;
> > +
> > + evict_walk.walk.arg.trylock_only = true;
> > + lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
> > target_bytes);
> > + if (lret < 0 || lret >= target_bytes)
> > + return lret;
> > +
> > + /* Second pass: also evict BOs at the low watermark. */
> > + if (evict_walk.hit_low) {
> > + evict_walk.try_low = true;
> > + pass = ttm_lru_walk_for_evict(&evict_walk.walk,
> > bdev, man,
> > + target_bytes -
> > lret);
> > + if (pass < 0)
> > + return pass;
> > + lret += pass;
> > + if (lret >= target_bytes)
> > + return lret;
> > + }
> > +
> > + /* Full sleeping-lock pass for remaining target. */
> > + evict_walk.try_low = evict_walk.hit_low = false;
> > + evict_walk.walk.arg.trylock_only = false;
> > +
> > +retry:
> > + evict_walk.walk.arg.sleeping_lock = true;
> > + do {
> > + evict_walk.evicted = 0;
> > + pass = ttm_lru_walk_for_evict(&evict_walk.walk,
> > bdev, man,
> > + target_bytes -
> > lret);
> > + if (pass < 0) {
> > + lret = pass;
> > + goto out;
> > + }
> > + lret += pass;
> > + } while (lret < target_bytes && evict_walk.evicted);
> > +
> > + /* One more attempt if we hit the low limit during
> > sleeping-lock pass. */
> > + if (lret < target_bytes && evict_walk.hit_low &&
> > !evict_walk.try_low) {
> > + evict_walk.try_low = true;
> > + goto retry;
> > + }
> > +
> > +out:
> > + return lret;
> > +}
> > +EXPORT_SYMBOL(ttm_bo_evict_cgroup);
> > +
> > /**
> > * ttm_bo_pin - Pin the buffer object.
> > * @bo: The buffer object to pin
> > diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c
> > b/drivers/gpu/drm/ttm/ttm_bo_util.c
> > index 3e3c201a0222..bd0b23ac2cc4 100644
> > --- a/drivers/gpu/drm/ttm/ttm_bo_util.c
> > +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
> > @@ -999,7 +999,8 @@ __ttm_bo_lru_cursor_next(struct
> > ttm_bo_lru_cursor *curs)
> > bo = res->bo;
> > if (ttm_lru_walk_trylock(curs, bo))
> > bo_locked = true;
> > - else if (!arg->ticket || arg->ctx->no_wait_gpu ||
> > arg->trylock_only)
> > + else if ((!arg->ticket && !arg->sleeping_lock) ||
> > arg->ctx->no_wait_gpu ||
> > + arg->trylock_only)
> > continue;
> >
> > if (!ttm_bo_get_unless_zero(bo)) {
> > diff --git a/drivers/gpu/drm/ttm/ttm_resource.c
> > b/drivers/gpu/drm/ttm/ttm_resource.c
> > index 154d6739256f..1ff4a470b083 100644
> > --- a/drivers/gpu/drm/ttm/ttm_resource.c
> > +++ b/drivers/gpu/drm/ttm/ttm_resource.c
> > @@ -953,3 +953,55 @@ void
> > ttm_resource_manager_create_debugfs(struct ttm_resource_manager
> > *man,
> > #endif
> > }
> > EXPORT_SYMBOL(ttm_resource_manager_create_debugfs);
> > +
> > +/**
> > + * ttm_resource_manager_dmem_reclaim() - dmem cgroup reclaim
> > callback for TTM
> > + * resource managers.
> > + * @pool: The dmem cgroup pool state for the cgroup being
> > reclaimed.
> > + * @target_bytes: Number of bytes to try to free.
> > + * @priv: The &ttm_resource_manager pointer, passed as
> > @init.reclaim_priv to
> > + * dmem_cgroup_register_region().
> > + *
> > + * Drivers should use this as the @reclaim member of their own
> > + * &struct dmem_cgroup_ops, with the &ttm_resource_manager pointer
> > as
> > + * @init.reclaim_priv.
> > + *
> > + * Return: 0 if some memory was freed, -ENOSPC if nothing was
> > freed, or
> > + * another negative error code on fatal failure.
> > + */
> > +int ttm_resource_manager_dmem_reclaim(struct
> > dmem_cgroup_pool_state *pool,
> > + u64 target_bytes, void
> > *priv)
> > +{
> > + struct ttm_resource_manager *man = priv;
> > + struct ttm_operation_ctx ctx = { .interruptible = true };
> > + s64 freed;
> > +
> > + freed = ttm_bo_evict_cgroup(man->bdev, man, pool,
> > target_bytes, &ctx);
> > + if (freed < 0)
> > + return freed;
> > +
> > + return freed > 0 ? 0 : -ENOSPC;
> > +}
> > +EXPORT_SYMBOL(ttm_resource_manager_dmem_reclaim);
> > +
> > +/**
> > + * ttm_resource_manager_set_dmem_region() - Associate a dmem
> > cgroup region with a
> > + * resource manager.
> > + * @man: The resource manager.
> > + * @region: The dmem cgroup region to associate, may be NULL or
> > IS_ERR().
> > + *
> > + * When @region is valid, stores it in @man->cg so that TTM can
> > look up the
> > + * associated pool during charging and eviction-target selection.
> > When
> > + * @region is %NULL, clears @man->cg to detach the region before
> > teardown.
> > + * An IS_ERR() @region is ignored, leaving @man->cg unchanged.
> > + * The reclaim callback must be wired up using
> > ttm_resource_manager_dmem_reclaim()
> > + * in the driver's own &struct dmem_cgroup_ops, with the manager
> > pointer as
> > + * @init.reclaim_priv.
> > + */
> > +void ttm_resource_manager_set_dmem_region(struct
> > ttm_resource_manager *man,
> > + struct
> > dmem_cgroup_region *region)
> > +{
> > + if (!IS_ERR(region))
> > + man->cg = region;
> > +}
> > +EXPORT_SYMBOL(ttm_resource_manager_set_dmem_region);
> > diff --git a/include/drm/ttm/ttm_bo.h b/include/drm/ttm/ttm_bo.h
> > index 8310bc3d55f9..32791c4db2a9 100644
> > --- a/include/drm/ttm/ttm_bo.h
> > +++ b/include/drm/ttm/ttm_bo.h
> > @@ -226,6 +226,11 @@ struct ttm_lru_walk_arg {
> > struct ww_acquire_ctx *ticket;
> > /** @trylock_only: Only use trylock for locking. */
> > bool trylock_only;
> > + /**
> > + * @sleeping_lock: Use sleeping locks even with %NULL
> > @ticket.
> > + * @trylock_only has precedence over this field.
> > + */
> > + bool sleeping_lock;
> > };
> >
> > /**
> > @@ -431,6 +436,11 @@ void ttm_bo_unpin(struct ttm_buffer_object
> > *bo);
> > int ttm_bo_evict_first(struct ttm_device *bdev,
> > struct ttm_resource_manager *man,
> > struct ttm_operation_ctx *ctx);
> > +s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
> > + struct ttm_resource_manager *man,
> > + struct dmem_cgroup_pool_state *limit_pool,
> > + s64 target_bytes,
> > + struct ttm_operation_ctx *ctx);
> > int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long
> > offset,
> > void *buf, int len, int write);
> > vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
> > diff --git a/include/drm/ttm/ttm_resource.h
> > b/include/drm/ttm/ttm_resource.h
> > index a5d386583fb6..32e485fdce9a 100644
> > --- a/include/drm/ttm/ttm_resource.h
> > +++ b/include/drm/ttm/ttm_resource.h
> > @@ -39,6 +39,7 @@
> >
> > struct dentry;
> > struct dmem_cgroup_device;
> > +struct dmem_cgroup_region;
> > struct drm_printer;
> > struct ttm_device;
> > struct ttm_resource_manager;
> > @@ -477,6 +478,12 @@ void ttm_resource_manager_init(struct
> > ttm_resource_manager *man,
> > struct ttm_device *bdev,
> > uint64_t size);
> >
> > +void ttm_resource_manager_set_dmem_region(struct
> > ttm_resource_manager *man,
> > + struct
> > dmem_cgroup_region *region);
> > +
> > +int ttm_resource_manager_dmem_reclaim(struct
> > dmem_cgroup_pool_state *pool,
> > + u64 target_bytes, void
> > *priv);
> > +
> > int ttm_resource_manager_evict_all(struct ttm_device *bdev,
> > struct ttm_resource_manager
> > *man);
> >
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-07-23 15:56 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 10:03 [PATCH v8 0/6] Add reclaim to the dmem cgroup controller Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 1/6] drm/amdgpu: Fix init ordering in amdgpu_vram_mgr_init() Thomas Hellström
2026-07-23 10:23 ` sashiko-bot
2026-07-23 10:03 ` [PATCH v8 2/6] cgroup/dmem: Introduce struct dmem_cgroup_init for region initialization Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 3/6] cgroup/dmem: Add reclaim callback for lowering max below current usage Thomas Hellström
2026-07-23 10:21 ` sashiko-bot
2026-07-23 10:03 ` [PATCH v8 4/6] drm/ttm: Hook up a cgroup-aware reclaim callback for the dmem controller Thomas Hellström
2026-07-23 10:31 ` sashiko-bot
2026-07-23 12:02 ` Maarten Lankhorst
2026-07-23 15:55 ` Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 5/6] drm/xe: Wire up dmem cgroup reclaim for VRAM manager Thomas Hellström
2026-07-23 10:03 ` [PATCH v8 6/6] drm/amdgpu: " Thomas Hellström
2026-07-23 10:50 ` sashiko-bot
2026-07-23 11:47 ` ✗ CI.checkpatch: warning for Add reclaim to the dmem cgroup controller (rev8) Patchwork
2026-07-23 11:48 ` ✓ CI.KUnit: success " Patchwork
2026-07-23 12:29 ` ✓ Xe.CI.BAT: " Patchwork
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.