Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670/* SPDX-License-Identifier: GPL-2.0-only OR MIT *//* * Copyright © 2024 Intel Corporation */
#ifndef __DRM_GPUSVM_H__#define __DRM_GPUSVM_H__
#include <linux/dma-mapping.h>#include <linux/kref.h>#include <linux/interval_tree.h>#include <linux/mmu_notifier.h>#include <drm/drm_pagemap.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_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_pages_flags - Structure representing a GPU SVM pages flags * * @unmapped: Flag indicating if the pages has been unmapped * @has_devmem_pages: Flag indicating if the pages has devmem pages * @has_dma_mapping: Flag indicating if the pages has a DMA mapping * @inline_dma_mapping: Flag indicating if the pages have an inline DMA mapping * @__flags: Flags for pages in u16 form (used for READ_ONCE) */struct drm_gpusvm_pages_flags { union { struct { /* All flags below must be set / cleared under notifier lock */ u16 unmapped : 1; u16 has_devmem_pages : 1; u16 has_dma_mapping : 1; u16 inline_dma_mapping : 1; }; u16 __flags; };};
/** * struct drm_gpusvm_pages - Structure representing a GPU SVM mapped pages * * @drm: The DRM device that owns the dma mappings * @dma_addr: Device address array, valid while @flags.inline_dma_mapping is * not set * @inline_addr: Device address inline address, valid while * @flags.inline_dma_mapping is set * @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. * @state: DMA IOVA state for mapping. * @state_offset: DMA IOVA offset for mapping. * @notifier_seq: Notifier sequence number of the range's pages * @flags: Flags for the range; see &struct drm_gpusvm_pages_flags * * @dma_addr and @inline_addr share storage, discriminated by * @flags.inline_dma_mapping. Driver should use drm_gpusvm_pages_first_dma() * to access the correct DMA address. */struct drm_gpusvm_pages { struct drm_device *drm; union { struct drm_pagemap_addr *dma_addr; struct drm_pagemap_addr inline_addr; }; struct drm_pagemap *dpagemap; struct dma_iova_state state; unsigned long state_offset; unsigned long notifier_seq; struct drm_gpusvm_pages_flags flags;};
/** * struct drm_gpusvm_range_flags - Range-level GPU SVM 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 * @__flags: All flags 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 __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 * @flags: Flags for range see &struct drm_gpusvm_range_flags * * 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; struct drm_gpusvm_range_flags flags;};
/** * struct drm_gpusvm - GPU SVM structure * * @name: Name of the GPU SVM * @mm: Pointer to the mm_struct for the address space * @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 mm_struct *mm; 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 * * @device_private_page_owner: The device-private page owner to use for * this operation * @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 * @allow_mixed: Allow mixed mappings in get pages. Mixing between system and * single dpagemap is supported, mixing between multiple dpagemap * is unsupported. * @no_dma_map: Only fault the CPU pages for the range; skip the device DMA * mapping step. Used by drivers that consume the faulted pages * without needing a DMA mapping. In this mode @drm on the * drm_gpusvm_pages is not required, no mapping state is recorded * and drm_gpusvm_pages_valid() therefore never reports these * pages as valid; the caller revalidates the snapshot itself, see * drm_gpusvm_get_pages(). @devmem_only is rejected and no page * type check is performed, so @allow_mixed has no effect. * @devmem_fn: Optional callback invoked under the notifier lock, once per * contiguous run of pages backed by the same &drm_pagemap_devmem. * Must not sleep and must be idempotent, as a non-contiguous * allocation is reported more than once. Fires even with * @no_dma_map. May be NULL. * * Context that is DRM GPUSVM is operating in (i.e. user arguments). */struct drm_gpusvm_ctx { void *device_private_page_owner; unsigned long check_pages_threshold; unsigned long timeslice_ms; void (*devmem_fn)(struct drm_pagemap_devmem *devmem); unsigned int in_notifier :1; unsigned int read_only :1; unsigned int devmem_possible :1; unsigned int devmem_only :1; unsigned int allow_mixed :1; unsigned int no_dma_map :1;};
int drm_gpusvm_init(struct drm_gpusvm *gpusvm, const char *name, struct mm_struct *mm, 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 longdrm_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_pages_valid(struct drm_gpusvm *gpusvm, struct drm_gpusvm_pages *svm_pages);
bool drm_gpusvm_has_mapping(struct drm_gpusvm *gpusvm, unsigned long start, unsigned long end);
struct drm_gpusvm_notifier *drm_gpusvm_notifier_find(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, struct drm_gpusvm_pages *pages, unsigned int pages_count, const struct mmu_notifier_range *mmu_range);
int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, struct drm_gpusvm_pages *svm_pages, unsigned int num_pages, struct mm_struct *mm, struct mmu_interval_notifier *notifier, unsigned long pages_start, unsigned long pages_end, const struct drm_gpusvm_ctx *ctx);
void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm, struct drm_gpusvm_pages *svm_pages, unsigned long npages, const struct drm_gpusvm_ctx *ctx);
void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm, struct drm_gpusvm_pages *svm_pages, unsigned long npages);
/** * drm_gpusvm_init_pages() - Initialize a freshly allocated drm_gpusvm_pages * @svm_pages: Pointer to the drm_gpusvm_pages to initialize. * @drm: The DRM device that will own DMA mappings for this pages object. * * Drivers that embed one or more drm_gpusvm_pages in their own range * structure must call this once on each pages instance after allocation, * before the first drm_gpusvm_get_pages() / unmap / free. */static inline void drm_gpusvm_init_pages(struct drm_gpusvm_pages *svm_pages, struct drm_device *drm){ memset(svm_pages, 0, sizeof(*svm_pages)); svm_pages->drm = drm; svm_pages->notifier_seq = LONG_MAX;}
/** * drm_gpusvm_pages_first_dma() - Resolve the device address array * @svm_pages: Pointer to the drm_gpusvm_pages. * @contiguous: Where to store whether one entry spans the whole range, or NULL * * drm_gpusvm_pages use unions to optimize the storage of DMA addresses, * this function abstracts the access to the first device address. The driver * should use this helper instead of reading dma_addr directly to prevent * array out of bounds access. * * @contiguous comes from the same read of the flags as the array itself, so a * caller cannot see the two disagree and walk past that single entry into the * fields behind it. When it is set the length comes from the range rather than * from the order. The order still states what one PTE may cover: the range * length for a huge page, PAGE_SIZE for an IOVA mapped range of single pages. * * Only get_pages() and the free path switch between the two union members. * Both hold the notifier lock for read, so taking that lock does not stop * them; callers need the driver lock that does, which every reader of the * addresses holds anyway. The notifier never touches the union, so the * pointer returned here stays good and can then be used under the notifier * lock. * * Return: Pointer to the first device address, NULL if none is populated. */static inline const struct drm_pagemap_addr *drm_gpusvm_pages_first_dma(const struct drm_gpusvm_pages *svm_pages, bool *contiguous){ struct drm_gpusvm_pages_flags flags = { /* READ_ONCE pairs with the WRITE_ONCE of the flag writers */ .__flags = READ_ONCE(svm_pages->flags.__flags), };
if (contiguous) *contiguous = flags.inline_dma_mapping;
if (flags.inline_dma_mapping) return &svm_pages->inline_addr;
return READ_ONCE(svm_pages->dma_addr);}
/** * enum drm_gpusvm_scan_result - Scan result from the drm_gpusvm_scan_mm() function. * @DRM_GPUSVM_SCAN_UNPOPULATED: At least one page was not present or inaccessible. * @DRM_GPUSVM_SCAN_EQUAL: All pages belong to the struct dev_pagemap indicated as * the @pagemap argument to the drm_gpusvm_scan_mm() function. * @DRM_GPUSVM_SCAN_OTHER: All pages belong to exactly one dev_pagemap, which is * *NOT* the @pagemap argument to the drm_gpusvm_scan_mm(). All pages belong to * the same device private owner. * @DRM_GPUSVM_SCAN_SYSTEM: All pages are present and system pages. * @DRM_GPUSVM_SCAN_MIXED_DEVICE: All pages are device pages and belong to at least * two different struct dev_pagemaps. All pages belong to the same device private * owner. * @DRM_GPUSVM_SCAN_MIXED: Pages are present and are a mix of system pages * and device-private pages. All device-private pages belong to the same device * private owner. */enum drm_gpusvm_scan_result { DRM_GPUSVM_SCAN_UNPOPULATED, DRM_GPUSVM_SCAN_EQUAL, DRM_GPUSVM_SCAN_OTHER, DRM_GPUSVM_SCAN_SYSTEM, DRM_GPUSVM_SCAN_MIXED_DEVICE, DRM_GPUSVM_SCAN_MIXED,};
enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range, void *dev_private_owner, const struct dev_pagemap *pagemap);
#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 longdrm_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 longdrm_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 longdrm_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 longdrm_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 longdrm_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 longdrm_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__))
/** * drm_gpusvm_for_each_range_safe() - Safely iterate over GPU SVM ranges in a notifier * @range__: Iterator variable for the ranges * @next__: Iterator variable for the ranges temporay storage * @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 while * removing ranges from it. */#define drm_gpusvm_for_each_range_safe(range__, next__, notifier__, start__, end__) \ for ((range__) = drm_gpusvm_range_find((notifier__), (start__), (end__)), \ (next__) = __drm_gpusvm_range_next(range__); \ (range__) && (drm_gpusvm_range_start(range__) < (end__)); \ (range__) = (next__), (next__) = __drm_gpusvm_range_next(range__))
/** * __drm_gpusvm_notifier_next() - get the next drm_gpusvm_notifier in the list * @notifier: a pointer to the current drm_gpusvm_notifier * * Return: A pointer to the next drm_gpusvm_notifier if available, or NULL if * the current notifier is the last one or if the input notifier is * NULL. */static inline struct drm_gpusvm_notifier *__drm_gpusvm_notifier_next(struct drm_gpusvm_notifier *notifier){ if (notifier && !list_is_last(¬ifier->entry, ¬ifier->gpusvm->notifier_list)) return list_next_entry(notifier, entry);
return NULL;}
/** * drm_gpusvm_for_each_notifier() - Iterate over GPU SVM notifiers in a gpusvm * @notifier__: Iterator variable for the notifiers * @gpusvm__: Pointer to the GPU SVM notifier * @start__: Start address of the notifier * @end__: End address of the notifier * * This macro is used to iterate over GPU SVM notifiers in a gpusvm. */#define drm_gpusvm_for_each_notifier(notifier__, gpusvm__, start__, end__) \ for ((notifier__) = drm_gpusvm_notifier_find((gpusvm__), (start__), (end__)); \ (notifier__) && (drm_gpusvm_notifier_start(notifier__) < (end__)); \ (notifier__) = __drm_gpusvm_notifier_next(notifier__))
/** * drm_gpusvm_for_each_notifier_safe() - Safely iterate over GPU SVM notifiers in a gpusvm * @notifier__: Iterator variable for the notifiers * @next__: Iterator variable for the notifiers temporay storage * @gpusvm__: Pointer to the GPU SVM notifier * @start__: Start address of the notifier * @end__: End address of the notifier * * This macro is used to iterate over GPU SVM notifiers in a gpusvm while * removing notifiers from it. */#define drm_gpusvm_for_each_notifier_safe(notifier__, next__, gpusvm__, start__, end__) \ for ((notifier__) = drm_gpusvm_notifier_find((gpusvm__), (start__), (end__)), \ (next__) = __drm_gpusvm_notifier_next(notifier__); \ (notifier__) && (drm_gpusvm_notifier_start(notifier__) < (end__)); \ (notifier__) = (next__), (next__) = __drm_gpusvm_notifier_next(notifier__))
#endif /* __DRM_GPUSVM_H__ */