Quelle drm_gpusvm.h
Sprache: C
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef __DRM_GPUSVM_H__
#define __DRM_GPUSVM_H__
#include <linux/kref.h>
#include <linux/interval_tree.h>
#include <linux/mmu_notifier.h>
struct dev_pagemap_ops;
struct drm_device;
struct drm_gpusvm;
struct drm_gpusvm_notifier;
struct drm_gpusvm_ops;
struct drm_gpusvm_range;
struct drm_pagemap;
struct drm_pagemap_device_addr;
/**
* struct drm_gpusvm_ops - Operations structure for GPU SVM
*
* This structure defines the operations for GPU Shared Virtual Memory ( SVM ) .
* These operations are provided by the GPU driver to manage SVM ranges and
* notifiers .
*/
struct drm_gpusvm_ops {
/**
* @ notifier_alloc : Allocate a GPU SVM notifier ( optional )
*
* Allocate a GPU SVM notifier .
*
* Return : Pointer to the allocated GPU SVM notifier on success , NULL on failure .
*/
struct drm_gpusvm_notifier *(*notifier_alloc)(void );
/**
* @ notifier_free : Free a GPU SVM notifier ( optional )
* @ notifier : Pointer to the GPU SVM notifier to be freed
*
* Free a GPU SVM notifier .
*/
void (*notifier_free)(struct drm_gpusvm_notifier *notifier);
/**
* @ range_alloc : Allocate a GPU SVM range ( optional )
* @ gpusvm : Pointer to the GPU SVM
*
* Allocate a GPU SVM range .
*
* Return : Pointer to the allocated GPU SVM range on success , NULL on failure .
*/
struct drm_gpusvm_range *(*range_alloc)(struct drm_gpusvm *gpusvm);
/**
* @ range_free : Free a GPU SVM range ( optional )
* @ range : Pointer to the GPU SVM range to be freed
*
* Free a GPU SVM range .
*/
void (*range_free)(struct drm_gpusvm_range *range);
/**
* @ invalidate : Invalidate GPU SVM notifier ( required )
* @ gpusvm : Pointer to the GPU SVM
* @ notifier : Pointer to the GPU SVM notifier
* @ mmu_range : Pointer to the mmu_notifier_range structure
*
* Invalidate the GPU page tables . It can safely walk the notifier range
* RB tree / list in this function . Called while holding the notifier lock .
*/
void (*invalidate)(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_notifier *notifier,
const struct mmu_notifier_range *mmu_range);
};
/**
* struct drm_gpusvm_notifier - Structure representing a GPU SVM notifier
*
* @ gpusvm : Pointer to the GPU SVM structure
* @ notifier : MMU interval notifier
* @ itree : Interval tree node for the notifier ( inserted in GPU SVM )
* @ entry : List entry to fast interval tree traversal
* @ root : Cached root node of the RB tree containing ranges
* @ range_list : List head containing of ranges in the same order they appear in
* interval tree . This is useful to keep iterating ranges while
* doing modifications to RB tree .
* @ flags : Flags for notifier
* @ flags . removed : Flag indicating whether the MMU interval notifier has been
* removed
*
* This structure represents a GPU SVM notifier .
*/
struct drm_gpusvm_notifier {
struct drm_gpusvm *gpusvm;
struct mmu_interval_notifier notifier;
struct interval_tree_node itree;
struct list_head entry;
struct rb_root_cached root;
struct list_head range_list;
struct {
u32 removed : 1 ;
} flags;
};
/**
* struct drm_gpusvm_range_flags - Structure representing a GPU SVM range flags
*
* @ migrate_devmem : Flag indicating whether the range can be migrated to device memory
* @ unmapped : Flag indicating if the range has been unmapped
* @ partial_unmap : Flag indicating if the range has been partially unmapped
* @ has_devmem_pages : Flag indicating if the range has devmem pages
* @ has_dma_mapping : Flag indicating if the range has a DMA mapping
* @ _ _ flags : Flags for range in u16 form ( used for READ_ONCE )
*/
struct drm_gpusvm_range_flags {
union {
struct {
/* All flags below must be set upon creation */
u16 migrate_devmem : 1 ;
/* All flags below must be set / cleared under notifier lock */
u16 unmapped : 1 ;
u16 partial_unmap : 1 ;
u16 has_devmem_pages : 1 ;
u16 has_dma_mapping : 1 ;
};
u16 __flags;
};
};
/**
* struct drm_gpusvm_range - Structure representing a GPU SVM range
*
* @ gpusvm : Pointer to the GPU SVM structure
* @ notifier : Pointer to the GPU SVM notifier
* @ refcount : Reference count for the range
* @ itree : Interval tree node for the range ( inserted in GPU SVM notifier )
* @ entry : List entry to fast interval tree traversal
* @ notifier_seq : Notifier sequence number of the range ' s pages
* @ dma_addr : Device address array
* @ dpagemap : The struct drm_pagemap of the device pages we ' re dma - mapping .
* Note this is assuming only one drm_pagemap per range is allowed .
* @ flags : Flags for range
*
* This structure represents a GPU SVM range used for tracking memory ranges
* mapped in a DRM device .
*/
struct drm_gpusvm_range {
struct drm_gpusvm *gpusvm;
struct drm_gpusvm_notifier *notifier;
struct kref refcount;
struct interval_tree_node itree;
struct list_head entry;
unsigned long notifier_seq;
struct drm_pagemap_device_addr *dma_addr;
struct drm_pagemap *dpagemap;
struct drm_gpusvm_range_flags flags;
};
/**
* struct drm_gpusvm - GPU SVM structure
*
* @ name : Name of the GPU SVM
* @ drm : Pointer to the DRM device structure
* @ mm : Pointer to the mm_struct for the address space
* @ device_private_page_owner : Device private pages owner
* @ mm_start : Start address of GPU SVM
* @ mm_range : Range of the GPU SVM
* @ notifier_size : Size of individual notifiers
* @ ops : Pointer to the operations structure for GPU SVM
* @ chunk_sizes : Pointer to the array of chunk sizes used in range allocation .
* Entries should be powers of 2 in descending order .
* @ num_chunks : Number of chunks
* @ notifier_lock : Read - write semaphore for protecting notifier operations
* @ root : Cached root node of the Red - Black tree containing GPU SVM notifiers
* @ notifier_list : list head containing of notifiers in the same order they
* appear in interval tree . This is useful to keep iterating
* notifiers while doing modifications to RB tree .
*
* This structure represents a GPU SVM ( Shared Virtual Memory ) used for tracking
* memory ranges mapped in a DRM ( Direct Rendering Manager ) device .
*
* No reference counting is provided , as this is expected to be embedded in the
* driver VM structure along with the struct drm_gpuvm , which handles reference
* counting .
*/
struct drm_gpusvm {
const char *name;
struct drm_device *drm;
struct mm_struct *mm;
void *device_private_page_owner;
unsigned long mm_start;
unsigned long mm_range;
unsigned long notifier_size;
const struct drm_gpusvm_ops *ops;
const unsigned long *chunk_sizes;
int num_chunks;
struct rw_semaphore notifier_lock;
struct rb_root_cached root;
struct list_head notifier_list;
#ifdef CONFIG_LOCKDEP
/**
* @ lock_dep_map : Annotates drm_gpusvm_range_find_or_insert and
* drm_gpusvm_range_remove with a driver provided lock .
*/
struct lockdep_map *lock_dep_map;
#endif
};
/**
* struct drm_gpusvm_ctx - DRM GPU SVM context
*
* @ check_pages_threshold : Check CPU pages for present if chunk is less than or
* equal to threshold . If not present , reduce chunk
* size .
* @ timeslice_ms : The timeslice MS which in minimum time a piece of memory
* remains with either exclusive GPU or CPU access .
* @ in_notifier : entering from a MMU notifier
* @ read_only : operating on read - only memory
* @ devmem_possible : possible to use device memory
* @ devmem_only : use only device memory
*
* Context that is DRM GPUSVM is operating in ( i . e . user arguments ) .
*/
struct drm_gpusvm_ctx {
unsigned long check_pages_threshold;
unsigned long timeslice_ms;
unsigned int in_notifier :1 ;
unsigned int read_only :1 ;
unsigned int devmem_possible :1 ;
unsigned int devmem_only :1 ;
};
int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
const char *name, struct drm_device *drm,
struct mm_struct *mm, void *device_private_page_owner,
unsigned long mm_start, unsigned long mm_range,
unsigned long notifier_size,
const struct drm_gpusvm_ops *ops,
const unsigned long *chunk_sizes, int num_chunks);
void drm_gpusvm_fini(struct drm_gpusvm *gpusvm);
void drm_gpusvm_free(struct drm_gpusvm *gpusvm);
unsigned long
drm_gpusvm_find_vma_start(struct drm_gpusvm *gpusvm,
unsigned long start,
unsigned long end);
struct drm_gpusvm_range *
drm_gpusvm_range_find_or_insert(struct drm_gpusvm *gpusvm,
unsigned long fault_addr,
unsigned long gpuva_start,
unsigned long gpuva_end,
const struct drm_gpusvm_ctx *ctx);
void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range);
int drm_gpusvm_range_evict(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range);
struct drm_gpusvm_range *
drm_gpusvm_range_get(struct drm_gpusvm_range *range);
void drm_gpusvm_range_put(struct drm_gpusvm_range *range);
bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range);
int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range,
const struct drm_gpusvm_ctx *ctx);
void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range,
const struct drm_gpusvm_ctx *ctx);
bool drm_gpusvm_has_mapping(struct drm_gpusvm *gpusvm, unsigned long start,
unsigned long end);
struct drm_gpusvm_range *
drm_gpusvm_range_find(struct drm_gpusvm_notifier *notifier, unsigned long start,
unsigned long end);
void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range,
const struct mmu_notifier_range *mmu_range);
#ifdef CONFIG_LOCKDEP
/**
* drm_gpusvm_driver_set_lock ( ) - Set the lock protecting accesses to GPU SVM
* @ gpusvm : Pointer to the GPU SVM structure .
* @ lock : the lock used to protect the gpuva list . The locking primitive
* must contain a dep_map field .
*
* Call this to annotate drm_gpusvm_range_find_or_insert and
* drm_gpusvm_range_remove .
*/
#define drm_gpusvm_driver_set_lock(gpusvm, lock) \
do { \
if (!WARN((gpusvm)->lock_dep_map, \
"GPUSVM range lock should be set only once." ))\
(gpusvm)->lock_dep_map = &(lock)->dep_map; \
} while (0 )
#else
#define drm_gpusvm_driver_set_lock(gpusvm, lock) do {} while (0 )
#endif
/**
* drm_gpusvm_notifier_lock ( ) - Lock GPU SVM notifier
* @ gpusvm__ : Pointer to the GPU SVM structure .
*
* Abstract client usage GPU SVM notifier lock , take lock
*/
#define drm_gpusvm_notifier_lock(gpusvm__) \
down_read(&(gpusvm__)->notifier_lock)
/**
* drm_gpusvm_notifier_unlock ( ) - Unlock GPU SVM notifier
* @ gpusvm__ : Pointer to the GPU SVM structure .
*
* Abstract client usage GPU SVM notifier lock , drop lock
*/
#define drm_gpusvm_notifier_unlock(gpusvm__) \
up_read(&(gpusvm__)->notifier_lock)
/**
* drm_gpusvm_range_start ( ) - GPU SVM range start address
* @ range : Pointer to the GPU SVM range
*
* Return : GPU SVM range start address
*/
static inline unsigned long
drm_gpusvm_range_start(struct drm_gpusvm_range *range)
{
return range->itree.start;
}
/**
* drm_gpusvm_range_end ( ) - GPU SVM range end address
* @ range : Pointer to the GPU SVM range
*
* Return : GPU SVM range end address
*/
static inline unsigned long
drm_gpusvm_range_end(struct drm_gpusvm_range *range)
{
return range->itree.last + 1 ;
}
/**
* drm_gpusvm_range_size ( ) - GPU SVM range size
* @ range : Pointer to the GPU SVM range
*
* Return : GPU SVM range size
*/
static inline unsigned long
drm_gpusvm_range_size(struct drm_gpusvm_range *range)
{
return drm_gpusvm_range_end(range) - drm_gpusvm_range_start(range);
}
/**
* drm_gpusvm_notifier_start ( ) - GPU SVM notifier start address
* @ notifier : Pointer to the GPU SVM notifier
*
* Return : GPU SVM notifier start address
*/
static inline unsigned long
drm_gpusvm_notifier_start(struct drm_gpusvm_notifier *notifier)
{
return notifier->itree.start;
}
/**
* drm_gpusvm_notifier_end ( ) - GPU SVM notifier end address
* @ notifier : Pointer to the GPU SVM notifier
*
* Return : GPU SVM notifier end address
*/
static inline unsigned long
drm_gpusvm_notifier_end(struct drm_gpusvm_notifier *notifier)
{
return notifier->itree.last + 1 ;
}
/**
* drm_gpusvm_notifier_size ( ) - GPU SVM notifier size
* @ notifier : Pointer to the GPU SVM notifier
*
* Return : GPU SVM notifier size
*/
static inline unsigned long
drm_gpusvm_notifier_size(struct drm_gpusvm_notifier *notifier)
{
return drm_gpusvm_notifier_end(notifier) -
drm_gpusvm_notifier_start(notifier);
}
/**
* _ _ drm_gpusvm_range_next ( ) - Get the next GPU SVM range in the list
* @ range : a pointer to the current GPU SVM range
*
* Return : A pointer to the next drm_gpusvm_range if available , or NULL if the
* current range is the last one or if the input range is NULL .
*/
static inline struct drm_gpusvm_range *
__drm_gpusvm_range_next(struct drm_gpusvm_range *range)
{
if (range && !list_is_last(&range->entry,
&range->notifier->range_list))
return list_next_entry(range, entry);
return NULL;
}
/**
* drm_gpusvm_for_each_range ( ) - Iterate over GPU SVM ranges in a notifier
* @ range__ : Iterator variable for the ranges . If set , it indicates the start of
* the iterator . If NULL , call drm_gpusvm_range_find ( ) to get the range .
* @ notifier__ : Pointer to the GPU SVM notifier
* @ start__ : Start address of the range
* @ end__ : End address of the range
*
* This macro is used to iterate over GPU SVM ranges in a notifier . It is safe
* to use while holding the driver SVM lock or the notifier lock .
*/
#define drm_gpusvm_for_each_range(range__, notifier__, start__, end__) \
for ((range__) = (range__) ?: \
drm_gpusvm_range_find((notifier__), (start__), (end__)); \
(range__) && (drm_gpusvm_range_start(range__) < (end__)); \
(range__) = __drm_gpusvm_range_next(range__))
#endif /* __DRM_GPUSVM_H__ */
Messung V0.5 in Prozent C=94 H=96 G=94
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland
2026-10-10
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1126438
#Domains=1897691