RAM is not, in fact, cheap. Especially on embedded systems with a low amount of memory, but known and well-defined userspace, more explicit resource management can lead to better utilisation patterns. As an example, a resource manager process on a purpose-built device may wish to launch, and then explicitly swap out, memory of processes that are kept "warm", to improve perceived startup latency of individual full-screen applications without making the kernel figure out the usage pattern from observation alone in order to swap out the right pages.
To allow for this explicit control in the context of panthor's GPU memory, add two new sysfs knobs. The first, mem_reclaim, runs an explicit priv BO reclaim cycle on the TGID written to it.
The second, mem_claim, does the opposite: it swaps BOs back into active memory.
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com --- Nicolas Frattaroli (4): drm/panthor: Add freed_sz parameter to reclaim_priv_bos MAINTAINERS: Add sysfs ABI docs to list of panthor files drm/panthor: Add explicit memory reclaim sysfs knob drm/panthor: Add explicit memory claim sysfs knob
Documentation/ABI/testing/sysfs-driver-panthor-mem | 34 ++++++++ MAINTAINERS | 1 + drivers/gpu/drm/panthor/panthor_drv.c | 93 ++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_gem.c | 7 +- drivers/gpu/drm/panthor/panthor_gem.h | 1 + drivers/gpu/drm/panthor/panthor_mmu.c | 70 +++++++++++++++- drivers/gpu/drm/panthor/panthor_mmu.h | 4 + 7 files changed, 205 insertions(+), 5 deletions(-) --- base-commit: 2c4b906cd135bbb44855287d0d0eff0ee0b47afe change-id: 20260506-panthor-explicit-reclaim-3dffed028d8c
Best regards, -- Nicolas Frattaroli nicolas.frattaroli@collabora.com
panthor_mmu_reclaim_priv_bos returns the number of freed pages. However, how many bytes of freed memory this translates to can't generally be deduced from the number of pages, as the page size is a per-VM property.
It may be useful to know the exact number of bytes that have been freed for observability and debugging purposes. To that end, add a new parameter "freed_sz", which is a pointer to a size_t where this information will be stored. It may be NULL, in which case the information isn't stored at all.
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com --- drivers/gpu/drm/panthor/panthor_gem.c | 3 ++- drivers/gpu/drm/panthor/panthor_mmu.c | 12 ++++++++++-- drivers/gpu/drm/panthor/panthor_mmu.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 13295d7a593d..80e82238f3c5 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -1511,7 +1511,8 @@ panthor_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) goto out;
freed += panthor_mmu_reclaim_priv_bos(ptdev, sc->nr_to_scan - freed, - &remaining, panthor_gem_try_evict); + &remaining, NULL, + panthor_gem_try_evict); if (freed >= sc->nr_to_scan) goto out;
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index a7ee14986849..b81388b35a58 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -3127,13 +3127,18 @@ int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec, struct panthor_vm unsigned long panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, unsigned int nr_to_scan, unsigned long *remaining, + size_t *freed_sz, bool (*shrink)(struct drm_gem_object *, struct ww_acquire_ctx *)) { + unsigned long newly_freed; unsigned long freed = 0; LIST_HEAD(remaining_vms); LIST_HEAD(vms);
+ if (freed_sz) + *freed_sz = 0; + mutex_lock(&ptdev->reclaim.lock); list_splice_init(&ptdev->reclaim.vms, &vms);
@@ -3152,8 +3157,11 @@ panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev,
mutex_unlock(&ptdev->reclaim.lock);
- freed += drm_gem_lru_scan(&vm->reclaim.lru, nr_to_scan - freed, - remaining, shrink, NULL); + newly_freed = drm_gem_lru_scan(&vm->reclaim.lru, nr_to_scan - freed, + remaining, shrink, NULL); + if (freed_sz) + *freed_sz += panthor_vm_page_size(vm) * newly_freed; + freed += newly_freed;
mutex_lock(&ptdev->reclaim.lock);
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/panthor/panthor_mmu.h index 3522fbbce369..12b18b5f90e1 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.h +++ b/drivers/gpu/drm/panthor/panthor_mmu.h @@ -52,6 +52,7 @@ int panthor_vm_evict_bo_mappings_locked(struct panthor_gem_object *bo); unsigned long panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, unsigned int nr_to_scan, unsigned long *remaining, + size_t *freed_sz, bool (*shrink)(struct drm_gem_object *, struct ww_acquire_ctx *)); int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec,
On 06/05/2026 11:45, Nicolas Frattaroli wrote:
panthor_mmu_reclaim_priv_bos returns the number of freed pages. However, how many bytes of freed memory this translates to can't generally be deduced from the number of pages, as the page size is a per-VM property.
It may be useful to know the exact number of bytes that have been freed
The "useful" aspect seems to just be a drm_dbg() message from what I can see with this series? Am I missing something or is it not actually that useful?
Thanks, Steve
for observability and debugging purposes. To that end, add a new parameter "freed_sz", which is a pointer to a size_t where this information will be stored. It may be NULL, in which case the information isn't stored at all.
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com
drivers/gpu/drm/panthor/panthor_gem.c | 3 ++- drivers/gpu/drm/panthor/panthor_mmu.c | 12 ++++++++++-- drivers/gpu/drm/panthor/panthor_mmu.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 13295d7a593d..80e82238f3c5 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -1511,7 +1511,8 @@ panthor_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) goto out; freed += panthor_mmu_reclaim_priv_bos(ptdev, sc->nr_to_scan - freed,
&remaining, panthor_gem_try_evict);
&remaining, NULL, if (freed >= sc->nr_to_scan) goto out;panthor_gem_try_evict);diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index a7ee14986849..b81388b35a58 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -3127,13 +3127,18 @@ int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec, struct panthor_vm unsigned long panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, unsigned int nr_to_scan, unsigned long *remaining,
size_t *freed_sz, bool (*shrink)(struct drm_gem_object *, struct ww_acquire_ctx *)){
- unsigned long newly_freed; unsigned long freed = 0; LIST_HEAD(remaining_vms); LIST_HEAD(vms);
- if (freed_sz)
*freed_sz = 0;- mutex_lock(&ptdev->reclaim.lock); list_splice_init(&ptdev->reclaim.vms, &vms);
@@ -3152,8 +3157,11 @@ panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, mutex_unlock(&ptdev->reclaim.lock);
freed += drm_gem_lru_scan(&vm->reclaim.lru, nr_to_scan - freed,remaining, shrink, NULL);
newly_freed = drm_gem_lru_scan(&vm->reclaim.lru, nr_to_scan - freed,remaining, shrink, NULL);if (freed_sz)*freed_sz += panthor_vm_page_size(vm) * newly_freed;freed += newly_freed;mutex_lock(&ptdev->reclaim.lock); diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/panthor/panthor_mmu.h index 3522fbbce369..12b18b5f90e1 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.h +++ b/drivers/gpu/drm/panthor/panthor_mmu.h @@ -52,6 +52,7 @@ int panthor_vm_evict_bo_mappings_locked(struct panthor_gem_object *bo); unsigned long panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, unsigned int nr_to_scan, unsigned long *remaining,
size_t *freed_sz, bool (*shrink)(struct drm_gem_object *, struct ww_acquire_ctx *));int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec,
On Wednesday, 6 May 2026 17:06:57 Central European Summer Time Steven Price wrote:
On 06/05/2026 11:45, Nicolas Frattaroli wrote:
panthor_mmu_reclaim_priv_bos returns the number of freed pages. However, how many bytes of freed memory this translates to can't generally be deduced from the number of pages, as the page size is a per-VM property.
It may be useful to know the exact number of bytes that have been freed
The "useful" aspect seems to just be a drm_dbg() message from what I can see with this series?
Correct.
Am I missing something or is it not actually that useful?
I wanted to know how much memory I'm actually reclaiming without making any assumptions about page sizes, and figured the change is innocent enough. If it's deemed too pointless, then I'll just drop the size in bytes from the debug message.
Kind regards, Nicolas Frattaroli
Thanks, Steve
for observability and debugging purposes. To that end, add a new parameter "freed_sz", which is a pointer to a size_t where this information will be stored. It may be NULL, in which case the information isn't stored at all.
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com
drivers/gpu/drm/panthor/panthor_gem.c | 3 ++- drivers/gpu/drm/panthor/panthor_mmu.c | 12 ++++++++++-- drivers/gpu/drm/panthor/panthor_mmu.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 13295d7a593d..80e82238f3c5 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -1511,7 +1511,8 @@ panthor_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) goto out; freed += panthor_mmu_reclaim_priv_bos(ptdev, sc->nr_to_scan - freed,
&remaining, panthor_gem_try_evict);
&remaining, NULL, if (freed >= sc->nr_to_scan) goto out;panthor_gem_try_evict);diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index a7ee14986849..b81388b35a58 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -3127,13 +3127,18 @@ int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec, struct panthor_vm unsigned long panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, unsigned int nr_to_scan, unsigned long *remaining,
size_t *freed_sz, bool (*shrink)(struct drm_gem_object *, struct ww_acquire_ctx *)){
- unsigned long newly_freed; unsigned long freed = 0; LIST_HEAD(remaining_vms); LIST_HEAD(vms);
- if (freed_sz)
*freed_sz = 0;- mutex_lock(&ptdev->reclaim.lock); list_splice_init(&ptdev->reclaim.vms, &vms);
@@ -3152,8 +3157,11 @@ panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, mutex_unlock(&ptdev->reclaim.lock);
freed += drm_gem_lru_scan(&vm->reclaim.lru, nr_to_scan - freed,remaining, shrink, NULL);
newly_freed = drm_gem_lru_scan(&vm->reclaim.lru, nr_to_scan - freed,remaining, shrink, NULL);if (freed_sz)*freed_sz += panthor_vm_page_size(vm) * newly_freed;freed += newly_freed;mutex_lock(&ptdev->reclaim.lock); diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/panthor/panthor_mmu.h index 3522fbbce369..12b18b5f90e1 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.h +++ b/drivers/gpu/drm/panthor/panthor_mmu.h @@ -52,6 +52,7 @@ int panthor_vm_evict_bo_mappings_locked(struct panthor_gem_object *bo); unsigned long panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, unsigned int nr_to_scan, unsigned long *remaining,
size_t *freed_sz, bool (*shrink)(struct drm_gem_object *, struct ww_acquire_ctx *));int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec,
While the ABI documentation in Documentation/ABI/ does include a contact person for each bit of ABI, this contact is not necessarily the same as the maintainers for the driver it touches.
Add panthor-specific sysfs ABI as tracked files to MAINTAINERS for panthor, to ensure that any changes to these files also go through the panthor maintainers.
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS index 5b897e9f4c73..f006ea21d99c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2205,6 +2205,7 @@ M: Liviu Dudau liviu.dudau@arm.com L: dri-devel@lists.freedesktop.org S: Supported T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/ABI/*/sysfs-driver-panthor-* F: Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml F: drivers/gpu/drm/ci/xfails/panthor* F: drivers/gpu/drm/panthor/
For deployments of systems with very tight memory and a system resource manager process that can make well-founded decisions on trade-offs, a way to tell panthor's GEM shrinker to run a reclaim on a specific process immediately is of interest.
Make it possible to do this by adding a new sysfs file, called "mem_reclaim", which kicks off a reclaim for private BOs owned by the process whose TGID is written to the file.
Processes may trigger an explicit reclaim on themselves, but triggering it on other processes requires the CAP_SYS_RESOURCE capability.
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com --- Documentation/ABI/testing/sysfs-driver-panthor-mem | 17 ++++++ drivers/gpu/drm/panthor/panthor_drv.c | 67 ++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_gem.c | 4 +- drivers/gpu/drm/panthor/panthor_gem.h | 1 + drivers/gpu/drm/panthor/panthor_mmu.c | 33 +++++++++++ drivers/gpu/drm/panthor/panthor_mmu.h | 2 + 6 files changed, 122 insertions(+), 2 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-driver-panthor-mem b/Documentation/ABI/testing/sysfs-driver-panthor-mem new file mode 100644 index 000000000000..6639394abed2 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-panthor-mem @@ -0,0 +1,17 @@ +What: /sys/bus/platform/drivers/panthor/.../mem_reclaim +Date: May 2026 +Contact: Nicolas Frattaroli nicolas.frattaroli@collabora.com +Description: + (WO) Writing to this file will trigger a GPU memory reclaim run for all + panthor GPU contexts associated with the TGID written to it. The write + completes when the reclaim operation has finished. + + To run a reclaim on a TGID other than its own, a process requires the + CAP_SYS_RESOURCE capability. + + Possible error codes: + * -ERANGE: given TGID is too large/small for the TGID type. + * -EINVAL: given TGID could not be parsed. + * -EPERM: insufficient permissions to run a reclaim on given TGID + * -EINTR: interrupted by signal + * -ESRCH: given TGID is not using panthor, and might not exist at all diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 66996c9147c2..7d19b8785ea3 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -1858,8 +1858,75 @@ static ssize_t profiling_store(struct device *dev,
static DEVICE_ATTR_RW(profiling);
+/** + * panthor_run_on_pfiles_of_tgid - Run function on each panthor_file of process + * @ptdev: pointer to the &struct panthor_device + * @tgid: The TGID of the process to look for + * @func: function pointer to run on every &struct panthor_file opened by @tgid + * + * Searches through the list of all panthor DRM files for ones that are opened + * by a process with TGID @tgid. For every match found, runs @func with the + * associated &struct panthor_file. + * + * Returns: negative errno on error, number of files matching @tgid otherwise. + */ +static int panthor_run_on_pfiles_of_tgid(struct panthor_device *ptdev, pid_t tgid, + void (*func)(struct panthor_file *pf)) +{ + struct drm_file *file; + int found = 0; + + scoped_cond_guard(mutex_intr, return -EINTR, &ptdev->base.filelist_mutex) { + list_for_each_entry(file, &ptdev->base.filelist, lhead) { + struct task_struct *task; + struct pid *file_pid; + + rcu_read_lock(); + file_pid = rcu_dereference(file->pid); + task = pid_task(file_pid, PIDTYPE_TGID); + if (!task || task->tgid != tgid) { + rcu_read_unlock(); + continue; + } + rcu_read_unlock(); + found++; + /* func needs to run outside RCU lock */ + func(file->driver_priv); + } + } + + return found; +} + +static ssize_t mem_reclaim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct panthor_device *ptdev = dev_get_drvdata(dev); + pid_t tgid; + int ret; + + ret = kstrtoint(buf, 0, &tgid); + if (ret) + return ret; + + if (tgid != current->tgid && !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + ret = panthor_run_on_pfiles_of_tgid(ptdev, tgid, panthor_mmu_force_reclaim); + if (ret < 0) + return ret; + else if (!ret) + return -ESRCH; + + return len; +} + +static DEVICE_ATTR_WO(mem_reclaim); + static struct attribute *panthor_attrs[] = { &dev_attr_profiling.attr, + &dev_attr_mem_reclaim.attr, NULL, };
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 80e82238f3c5..5780fd51170c 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -1473,8 +1473,8 @@ static bool panthor_gem_try_evict_no_resv_wait(struct drm_gem_object *obj, return ret == 0; }
-static bool panthor_gem_try_evict(struct drm_gem_object *obj, - struct ww_acquire_ctx *ticket) +bool panthor_gem_try_evict(struct drm_gem_object *obj, + struct ww_acquire_ctx *ticket) { struct panthor_gem_object *bo = to_panthor_bo(obj);
diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index ae0491d0b121..593d8e7b7aaf 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -254,6 +254,7 @@ panthor_gem_get_dev_sgt(struct panthor_gem_object *bo); int panthor_gem_pin(struct panthor_gem_object *bo); void panthor_gem_unpin(struct panthor_gem_object *bo); int panthor_gem_swapin_locked(struct panthor_gem_object *bo); +bool panthor_gem_try_evict(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket); void panthor_gem_update_reclaim_state_locked(struct panthor_gem_object *bo, enum panthor_gem_reclaim_state *old_state); int panthor_gem_shrinker_init(struct panthor_device *ptdev); diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index b81388b35a58..e185787f5657 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -3199,6 +3199,39 @@ panthor_mmu_reclaim_priv_bos(struct panthor_device *ptdev, return freed; }
+/** + * panthor_mmu_force_reclaim - Run a reclaim on all VMs associated with a file + * @pfile: pointer to the &struct panthor_file to reclaim memory on + * + * Attempt to evict all private BOs of VMs associated with @pfile. In other + * words, attempt to swap out as much GPU memory of the context associated with + * @pfile as possible. + */ +void panthor_mmu_force_reclaim(struct panthor_file *pfile) +{ + struct panthor_device *ptdev = pfile->ptdev; + unsigned long i, remaining, freed; + unsigned int nr_to_scan = 0; + struct panthor_vm *vm; + size_t freed_sz; + + scoped_guard(mutex, &ptdev->reclaim.lock) { + xa_for_each(&pfile->vms->xa, i, vm) { + /* Skip VMs that already aren't backed by any pages */ + if (!vm->reclaim.lru.count) + continue; + + nr_to_scan += vm->reclaim.lru.count; + list_move(&vm->reclaim.lru_node, &ptdev->reclaim.vms); + } + } + freed = panthor_mmu_reclaim_priv_bos(ptdev, nr_to_scan, &remaining, + &freed_sz, panthor_gem_try_evict); + drm_dbg(&ptdev->base, + "Reclaimed %lu pages (%zu bytes) out of %u scanned, with %lu remaining\n", + freed, freed_sz, nr_to_scan, remaining); +} + /** * panthor_mmu_unplug() - Unplug the MMU logic * @ptdev: Device. diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/panthor/panthor_mmu.h index 12b18b5f90e1..34adca4b4e95 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.h +++ b/drivers/gpu/drm/panthor/panthor_mmu.h @@ -11,6 +11,7 @@ struct drm_exec; struct drm_sched_job; struct drm_memory_stats; +struct panthor_file; struct panthor_gem_object; struct panthor_heap_pool; struct panthor_vm; @@ -23,6 +24,7 @@ void panthor_mmu_pre_reset(struct panthor_device *ptdev); void panthor_mmu_post_reset(struct panthor_device *ptdev); void panthor_mmu_suspend(struct panthor_device *ptdev); void panthor_mmu_resume(struct panthor_device *ptdev); +void panthor_mmu_force_reclaim(struct panthor_file *pfile);
int panthor_vm_map_bo_range(struct panthor_vm *vm, struct panthor_gem_object *bo, u64 offset, u64 size, u64 va, u32 flags);
For deployments of systems with very tight memory and a system resource manager process that can make well-founded decisions on trade-offs, a way to tell panthor that all of a process' swapped-out GPU memory should be swapped back in without touching every page manually is of interest.
Make it possible to do this by adding a new sysfs file, called "mem_claim". Writing a TGID to it will cause panthor to search through all panthor_files associated with that process, and bring all its buffers back from swap.
Doing this requires the writer to have the CAP_SYS_RESOURCE capability, even when operating on themselves.
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com --- Documentation/ABI/testing/sysfs-driver-panthor-mem | 17 ++++++++++++++ drivers/gpu/drm/panthor/panthor_drv.c | 26 ++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_mmu.c | 25 +++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_mmu.h | 1 + 4 files changed, 69 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-driver-panthor-mem b/Documentation/ABI/testing/sysfs-driver-panthor-mem index 6639394abed2..41e2c18f641d 100644 --- a/Documentation/ABI/testing/sysfs-driver-panthor-mem +++ b/Documentation/ABI/testing/sysfs-driver-panthor-mem @@ -15,3 +15,20 @@ Description: * -EPERM: insufficient permissions to run a reclaim on given TGID * -EINTR: interrupted by signal * -ESRCH: given TGID is not using panthor, and might not exist at all + +What: /sys/bus/platform/drivers/panthor/.../mem_claim +Date: May 2026 +Contact: Nicolas Frattaroli nicolas.frattaroli@collabora.com +Description: + (WO) Writing to this file will cause GPU memory for all panthor GPU + contexts associated with the TGID that's written to it to be brought + back from swap. The write completes when the operation has finished. + + The writing process requires the CAP_SYS_RESOURCE capability. + + Possible error codes: + * -ERANGE: given TGID is too large/small for the TGID type. + * -EINVAL: given TGID could not be parsed. + * -EPERM: insufficient permissions + * -EINTR: interrupted by signal + * -ESRCH: given TGID is not using panthor, and might not exist at all diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 7d19b8785ea3..fb2172b0439c 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -1924,9 +1924,35 @@ static ssize_t mem_reclaim_store(struct device *dev,
static DEVICE_ATTR_WO(mem_reclaim);
+static ssize_t mem_claim_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct panthor_device *ptdev = dev_get_drvdata(dev); + pid_t tgid; + int ret; + + ret = kstrtoint(buf, 0, &tgid); + if (ret) + return ret; + + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; + + ret = panthor_run_on_pfiles_of_tgid(ptdev, tgid, panthor_mmu_force_claim); + if (ret < 0) + return ret; + else if (!ret) + return -ESRCH; + + return len; +} + +static DEVICE_ATTR_WO(mem_claim); + static struct attribute *panthor_attrs[] = { &dev_attr_profiling.attr, &dev_attr_mem_reclaim.attr, + &dev_attr_mem_claim.attr, NULL, };
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index e185787f5657..7130ba4a24da 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -3232,6 +3232,31 @@ void panthor_mmu_force_reclaim(struct panthor_file *pfile) freed, freed_sz, nr_to_scan, remaining); }
+/** + * panthor_mmu_force_claim - Swap in all VMs associated with a file + * @pfile: pointer to the &struct panthor_file whose memory to swap in + * + * Attempt to get all GPU memory of @pfile swapped back in. + */ +void panthor_mmu_force_claim(struct panthor_file *pfile) +{ + struct panthor_vm *vm; + unsigned long i; + int ret; + + xa_for_each(&pfile->vms->xa, i, vm) { + struct dma_resv *resv = drm_gpuvm_resv(&vm->base); + + dma_resv_lock(resv, NULL); + ret = drm_gpuvm_validate(&vm->base, NULL); + if (ret) + drm_dbg(&vm->ptdev->base, "drm_gpuvm_validate failed: %pe\n", + ERR_PTR(ret)); + + dma_resv_unlock(resv); + } +} + /** * panthor_mmu_unplug() - Unplug the MMU logic * @ptdev: Device. diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/panthor/panthor_mmu.h index 34adca4b4e95..460f83eb22a9 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.h +++ b/drivers/gpu/drm/panthor/panthor_mmu.h @@ -25,6 +25,7 @@ void panthor_mmu_post_reset(struct panthor_device *ptdev); void panthor_mmu_suspend(struct panthor_device *ptdev); void panthor_mmu_resume(struct panthor_device *ptdev); void panthor_mmu_force_reclaim(struct panthor_file *pfile); +void panthor_mmu_force_claim(struct panthor_file *pfile);
int panthor_vm_map_bo_range(struct panthor_vm *vm, struct panthor_gem_object *bo, u64 offset, u64 size, u64 va, u32 flags);
On 06/05/2026 11:45, Nicolas Frattaroli wrote:
RAM is not, in fact, cheap. Especially on embedded systems with a low amount of memory, but known and well-defined userspace, more explicit resource management can lead to better utilisation patterns. As an example, a resource manager process on a purpose-built device may wish to launch, and then explicitly swap out, memory of processes that are kept "warm", to improve perceived startup latency of individual full-screen applications without making the kernel figure out the usage pattern from observation alone in order to swap out the right pages.
Have you considered memory control groups (memcg) for this purpose? Imposing a lower limit than currently allocated should trigger reclaim, so 'background' applications could have the limit lowered and then restored when moved to the foreground.
To allow for this explicit control in the context of panthor's GPU memory, add two new sysfs knobs. The first, mem_reclaim, runs an explicit priv BO reclaim cycle on the TGID written to it.
The second, mem_claim, does the opposite: it swaps BOs back into active memory.
How necessary is this mem_claim for performance? Have you done any benchmarking of explicitly claiming vs just allowing it to happen naturally? My gut feeling is that mem_claim should be unnecessary in most situations, but I'm prepared to be proved wrong.
I'm not saying this series is necessarily the wrong approach - but I think we need a bit more justification for adding a new API for this.
Thanks, Steve
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com
Nicolas Frattaroli (4): drm/panthor: Add freed_sz parameter to reclaim_priv_bos MAINTAINERS: Add sysfs ABI docs to list of panthor files drm/panthor: Add explicit memory reclaim sysfs knob drm/panthor: Add explicit memory claim sysfs knob
Documentation/ABI/testing/sysfs-driver-panthor-mem | 34 ++++++++ MAINTAINERS | 1 + drivers/gpu/drm/panthor/panthor_drv.c | 93 ++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_gem.c | 7 +- drivers/gpu/drm/panthor/panthor_gem.h | 1 + drivers/gpu/drm/panthor/panthor_mmu.c | 70 +++++++++++++++- drivers/gpu/drm/panthor/panthor_mmu.h | 4 + 7 files changed, 205 insertions(+), 5 deletions(-)
base-commit: 2c4b906cd135bbb44855287d0d0eff0ee0b47afe change-id: 20260506-panthor-explicit-reclaim-3dffed028d8c
Best regards,
Nicolas Frattaroli nicolas.frattaroli@collabora.com
On Wednesday, 6 May 2026 17:06:56 Central European Summer Time Steven Price wrote:
On 06/05/2026 11:45, Nicolas Frattaroli wrote:
RAM is not, in fact, cheap. Especially on embedded systems with a low amount of memory, but known and well-defined userspace, more explicit resource management can lead to better utilisation patterns. As an example, a resource manager process on a purpose-built device may wish to launch, and then explicitly swap out, memory of processes that are kept "warm", to improve perceived startup latency of individual full-screen applications without making the kernel figure out the usage pattern from observation alone in order to swap out the right pages.
Have you considered memory control groups (memcg) for this purpose? Imposing a lower limit than currently allocated should trigger reclaim, so 'background' applications could have the limit lowered and then restored when moved to the foreground.
This is a suggestion in line with what I've made to the entity for whom I am adding this, but was told that for them they really do want tight control without having to use cgroups into technically doing it by dynamically adjusting the limits of them.
I do think that writing 0 to `memory.high` to swap it out and `"max"` to allow it to swap back in might work, though that'll then apply to all of the process' memory, not just the GPU resources.
I will ask for clarification internally.
To allow for this explicit control in the context of panthor's GPU memory, add two new sysfs knobs. The first, mem_reclaim, runs an explicit priv BO reclaim cycle on the TGID written to it.
The second, mem_claim, does the opposite: it swaps BOs back into active memory.
How necessary is this mem_claim for performance? Have you done any benchmarking of explicitly claiming vs just allowing it to happen naturally? My gut feeling is that mem_claim should be unnecessary in most situations, but I'm prepared to be proved wrong.
I've done no benchmarking, but can do so if you have any preferred workloads for this. Since we have to keep entire groups either in memory or out of memory right now AFAIK, I don't expect this to be very beneficial at all. At most we avoid a single fault I think.
I can drop the mem_claim part, though it may become relevant if we ever have more fine-grained memory eviction where a single job or group can run into multiple faults before everything it needs to render a new frame is back in memory. In that case, it will be beneficial, because it avoids doing the swap-in dance several times while the user wonders why the UI is rendering at powerpoint speeds as it touches memory pages that are still swapped out during subsequent frames.
I'm not saying this series is necessarily the wrong approach - but I think we need a bit more justification for adding a new API for this.
Thanks, Steve
Kind regards, Nicolas Frattaroli
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com
Nicolas Frattaroli (4): drm/panthor: Add freed_sz parameter to reclaim_priv_bos MAINTAINERS: Add sysfs ABI docs to list of panthor files drm/panthor: Add explicit memory reclaim sysfs knob drm/panthor: Add explicit memory claim sysfs knob
Documentation/ABI/testing/sysfs-driver-panthor-mem | 34 ++++++++ MAINTAINERS | 1 + drivers/gpu/drm/panthor/panthor_drv.c | 93 ++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_gem.c | 7 +- drivers/gpu/drm/panthor/panthor_gem.h | 1 + drivers/gpu/drm/panthor/panthor_mmu.c | 70 +++++++++++++++- drivers/gpu/drm/panthor/panthor_mmu.h | 4 + 7 files changed, 205 insertions(+), 5 deletions(-)
base-commit: 2c4b906cd135bbb44855287d0d0eff0ee0b47afe change-id: 20260506-panthor-explicit-reclaim-3dffed028d8c
Best regards,
Nicolas Frattaroli nicolas.frattaroli@collabora.com
On 06/05/2026 16:43, Nicolas Frattaroli wrote:
On Wednesday, 6 May 2026 17:06:56 Central European Summer Time Steven Price wrote:
On 06/05/2026 11:45, Nicolas Frattaroli wrote:
RAM is not, in fact, cheap. Especially on embedded systems with a low amount of memory, but known and well-defined userspace, more explicit resource management can lead to better utilisation patterns. As an example, a resource manager process on a purpose-built device may wish to launch, and then explicitly swap out, memory of processes that are kept "warm", to improve perceived startup latency of individual full-screen applications without making the kernel figure out the usage pattern from observation alone in order to swap out the right pages.
Have you considered memory control groups (memcg) for this purpose? Imposing a lower limit than currently allocated should trigger reclaim, so 'background' applications could have the limit lowered and then restored when moved to the foreground.
This is a suggestion in line with what I've made to the entity for whom I am adding this, but was told that for them they really do want tight control without having to use cgroups into technically doing it by dynamically adjusting the limits of them.
I do think that writing 0 to `memory.high` to swap it out and `"max"` to allow it to swap back in might work, though that'll then apply to all of the process' memory, not just the GPU resources.
I will ask for clarification internally.
Thanks, it would be good to have a better understanding of why GPU memory is special (and needs to be paged out) and the process' other memory can be kept.
To allow for this explicit control in the context of panthor's GPU memory, add two new sysfs knobs. The first, mem_reclaim, runs an explicit priv BO reclaim cycle on the TGID written to it.
The second, mem_claim, does the opposite: it swaps BOs back into active memory.
How necessary is this mem_claim for performance? Have you done any benchmarking of explicitly claiming vs just allowing it to happen naturally? My gut feeling is that mem_claim should be unnecessary in most situations, but I'm prepared to be proved wrong.
I've done no benchmarking, but can do so if you have any preferred workloads for this. Since we have to keep entire groups either in memory or out of memory right now AFAIK, I don't expect this to be very beneficial at all. At most we avoid a single fault I think.
Yes the memory should be brought back in as soon as a job is submitted. I've no particular workloads in mind - but it would be nice to be able to point to something that actually improves by adding this feature.
I can drop the mem_claim part, though it may become relevant if we ever have more fine-grained memory eviction where a single job or group can run into multiple faults before everything it needs to render a new frame is back in memory. In that case, it will be beneficial, because it avoids doing the swap-in dance several times while the user wonders why the UI is rendering at powerpoint speeds as it touches memory pages that are still swapped out during subsequent frames.
We don't want to be faulting memory in a page at a time for exactly the reasons you state. So even if we do make things more fine-grained we're going to have to implement some form of read-ahead. Otherwise it's "powerpoint time" after any even that causes memory pressure.
A possible justification is if the system can tell an application is about to be used and can "pre-fault" things before rendering starts. But it's a rare system design where it has this form of precognition.
Thanks, Steve
I'm not saying this series is necessarily the wrong approach - but I think we need a bit more justification for adding a new API for this.
Thanks, Steve
Kind regards, Nicolas Frattaroli
Signed-off-by: Nicolas Frattaroli nicolas.frattaroli@collabora.com
Nicolas Frattaroli (4): drm/panthor: Add freed_sz parameter to reclaim_priv_bos MAINTAINERS: Add sysfs ABI docs to list of panthor files drm/panthor: Add explicit memory reclaim sysfs knob drm/panthor: Add explicit memory claim sysfs knob
Documentation/ABI/testing/sysfs-driver-panthor-mem | 34 ++++++++ MAINTAINERS | 1 + drivers/gpu/drm/panthor/panthor_drv.c | 93 ++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_gem.c | 7 +- drivers/gpu/drm/panthor/panthor_gem.h | 1 + drivers/gpu/drm/panthor/panthor_mmu.c | 70 +++++++++++++++- drivers/gpu/drm/panthor/panthor_mmu.h | 4 + 7 files changed, 205 insertions(+), 5 deletions(-)
base-commit: 2c4b906cd135bbb44855287d0d0eff0ee0b47afe change-id: 20260506-panthor-explicit-reclaim-3dffed028d8c
Best regards,
Nicolas Frattaroli nicolas.frattaroli@collabora.com
linaro-mm-sig@lists.linaro.org