mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
drm/pagemap: Add a drm_pagemap cache and shrinker
Pagemaps are costly to set up and tear down, and they consume a lot of system memory for the struct pages. Ideally they should be created only when needed. Add a caching mechanism to allow doing just that: Create the drm_pagemaps when needed for migration. Keep them around to avoid destruction and re-creation latencies and destroy inactive/unused drm_pagemaps on memory pressure using a shrinker. Only add the helper functions. They will be hooked up to the xe driver in the upcoming patch. v2: - Add lockdep checking for drm_pagemap_put(). (Matt Brost) - Add a copyright notice. (Matt Brost) Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com> Reviewed-by: Matthew Brost <matthew.brost@intel.com> Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> # For merging through drm-xe. Link: https://patch.msgid.link/20251219113320.183860-8-thomas.hellstrom@linux.intel.com
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
struct dma_fence;
|
||||
struct drm_pagemap;
|
||||
struct drm_pagemap_cache;
|
||||
struct drm_pagemap_dev_hold;
|
||||
struct drm_pagemap_zdd;
|
||||
struct device;
|
||||
@@ -125,6 +126,25 @@ struct drm_pagemap_ops {
|
||||
unsigned long start, unsigned long end,
|
||||
struct mm_struct *mm,
|
||||
unsigned long timeslice_ms);
|
||||
/**
|
||||
* @destroy: Destroy the drm_pagemap and associated resources.
|
||||
* @dpagemap: The drm_pagemap to destroy.
|
||||
* @is_atomic_or_reclaim: The function may be called from
|
||||
* atomic- or reclaim context.
|
||||
*
|
||||
* The implementation should take care not to attempt to
|
||||
* destroy resources that may already have been destroyed
|
||||
* using devm_ callbacks, since this function may be called
|
||||
* after the underlying struct device has been unbound.
|
||||
* If the implementation defers the execution to a work item
|
||||
* to avoid locking issues, then it must make sure the work
|
||||
* items are flushed before module exit. If the destroy call
|
||||
* happens after the provider's pci_remove() callback has
|
||||
* been executed, a module reference and drm device reference is
|
||||
* held across the destroy callback.
|
||||
*/
|
||||
void (*destroy)(struct drm_pagemap *dpagemap,
|
||||
bool is_atomic_or_reclaim);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -136,6 +156,10 @@ struct drm_pagemap_ops {
|
||||
* @pagemap: Pointer to the underlying dev_pagemap.
|
||||
* @dev_hold: Pointer to a struct drm_pagemap_dev_hold for
|
||||
* device referencing.
|
||||
* @cache: Back-pointer to the &struct drm_pagemap_cache used for this
|
||||
* &struct drm_pagemap. May be NULL if no cache is used.
|
||||
* @shrink_link: Link into the shrinker's list of drm_pagemaps. Only
|
||||
* used if also using a pagemap cache.
|
||||
*/
|
||||
struct drm_pagemap {
|
||||
const struct drm_pagemap_ops *ops;
|
||||
@@ -143,6 +167,8 @@ struct drm_pagemap {
|
||||
struct drm_device *drm;
|
||||
struct dev_pagemap *pagemap;
|
||||
struct drm_pagemap_dev_hold *dev_hold;
|
||||
struct drm_pagemap_cache *cache;
|
||||
struct list_head shrink_link;
|
||||
};
|
||||
|
||||
struct drm_pagemap_devmem;
|
||||
@@ -217,6 +243,11 @@ struct drm_pagemap_devmem_ops {
|
||||
struct dma_fence *pre_migrate_fence);
|
||||
};
|
||||
|
||||
int drm_pagemap_init(struct drm_pagemap *dpagemap,
|
||||
struct dev_pagemap *pagemap,
|
||||
struct drm_device *drm,
|
||||
const struct drm_pagemap_ops *ops);
|
||||
|
||||
struct drm_pagemap *drm_pagemap_create(struct drm_device *drm,
|
||||
struct dev_pagemap *pagemap,
|
||||
const struct drm_pagemap_ops *ops);
|
||||
@@ -235,9 +266,9 @@ static inline void drm_pagemap_put(struct drm_pagemap *dpagemap)
|
||||
|
||||
/**
|
||||
* drm_pagemap_get() - Obtain a reference on a struct drm_pagemap
|
||||
* @dpagemap: Pointer to the struct drm_pagemap.
|
||||
* @dpagemap: Pointer to the struct drm_pagemap, or NULL.
|
||||
*
|
||||
* Return: Pointer to the struct drm_pagemap.
|
||||
* Return: Pointer to the struct drm_pagemap, or NULL.
|
||||
*/
|
||||
static inline struct drm_pagemap *
|
||||
drm_pagemap_get(struct drm_pagemap *dpagemap)
|
||||
@@ -248,6 +279,20 @@ drm_pagemap_get(struct drm_pagemap *dpagemap)
|
||||
return dpagemap;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_pagemap_get_unless_zero() - Obtain a reference on a struct drm_pagemap
|
||||
* unless the current reference count is zero.
|
||||
* @dpagemap: Pointer to the drm_pagemap or NULL.
|
||||
*
|
||||
* Return: A pointer to @dpagemap if the reference count was successfully
|
||||
* incremented. NULL if @dpagemap was NULL, or its refcount was 0.
|
||||
*/
|
||||
static inline struct drm_pagemap * __must_check
|
||||
drm_pagemap_get_unless_zero(struct drm_pagemap *dpagemap)
|
||||
{
|
||||
return (dpagemap && kref_get_unless_zero(&dpagemap->ref)) ? dpagemap : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct drm_pagemap_devmem - Structure representing a GPU SVM device memory allocation
|
||||
*
|
||||
@@ -295,5 +340,7 @@ int drm_pagemap_populate_mm(struct drm_pagemap *dpagemap,
|
||||
struct mm_struct *mm,
|
||||
unsigned long timeslice_ms);
|
||||
|
||||
#endif
|
||||
void drm_pagemap_destroy(struct drm_pagemap *dpagemap, bool is_atomic_or_reclaim);
|
||||
|
||||
int drm_pagemap_reinit(struct drm_pagemap *dpagemap);
|
||||
#endif
|
||||
|
||||
42
include/drm/drm_pagemap_util.h
Normal file
42
include/drm/drm_pagemap_util.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef _DRM_PAGEMAP_UTIL_H_
|
||||
#define _DRM_PAGEMAP_UTIL_H_
|
||||
|
||||
struct drm_device;
|
||||
struct drm_pagemap;
|
||||
struct drm_pagemap_cache;
|
||||
struct drm_pagemap_shrinker;
|
||||
|
||||
void drm_pagemap_shrinker_add(struct drm_pagemap *dpagemap);
|
||||
|
||||
int drm_pagemap_cache_lock_lookup(struct drm_pagemap_cache *cache);
|
||||
|
||||
void drm_pagemap_cache_unlock_lookup(struct drm_pagemap_cache *cache);
|
||||
|
||||
struct drm_pagemap_shrinker *drm_pagemap_shrinker_create_devm(struct drm_device *drm);
|
||||
|
||||
struct drm_pagemap_cache *drm_pagemap_cache_create_devm(struct drm_pagemap_shrinker *shrinker);
|
||||
|
||||
struct drm_pagemap *drm_pagemap_get_from_cache(struct drm_pagemap_cache *cache);
|
||||
|
||||
void drm_pagemap_cache_set_pagemap(struct drm_pagemap_cache *cache, struct drm_pagemap *dpagemap);
|
||||
|
||||
struct drm_pagemap *drm_pagemap_get_from_cache_if_active(struct drm_pagemap_cache *cache);
|
||||
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
|
||||
void drm_pagemap_shrinker_might_lock(struct drm_pagemap *dpagemap);
|
||||
|
||||
#else
|
||||
|
||||
static inline void drm_pagemap_shrinker_might_lock(struct drm_pagemap *dpagemap)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PROVE_LOCKING */
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user