1 /* SPDX-License-Identifier: MIT */ 2 /* 3 * Copyright © 2024 Intel Corporation 4 */ 5 #ifndef _XE_VALIDATION_H_ 6 #define _XE_VALIDATION_H_ 7 8 #include <linux/dma-resv.h> 9 #include <linux/types.h> 10 #include <linux/rwsem.h> 11 12 struct drm_exec; 13 struct drm_gem_object; 14 struct drm_gpuvm_exec; 15 struct xe_device; 16 17 #ifdef CONFIG_PROVE_LOCKING 18 /** 19 * xe_validation_lockdep() - Assert that a drm_exec locking transaction can 20 * be initialized at this point. 21 */ 22 static inline void xe_validation_lockdep(void) 23 { 24 struct ww_acquire_ctx ticket; 25 26 ww_acquire_init(&ticket, &reservation_ww_class); 27 ww_acquire_fini(&ticket); 28 } 29 #else 30 static inline void xe_validation_lockdep(void) 31 { 32 } 33 #endif 34 35 /* 36 * Various values of the drm_exec pointer where we've not (yet) 37 * implemented full ww locking. 38 * 39 * XE_VALIDATION_UNIMPLEMENTED means implementation is pending. 40 * A lockdep check is made to assure that a drm_exec locking 41 * transaction can actually take place where the macro is 42 * used. If this asserts, the exec pointer needs to be assigned 43 * higher up in the callchain and passed down. 44 * 45 * XE_VALIDATION_UNSUPPORTED is for dma-buf code only where 46 * the dma-buf layer doesn't support WW locking. 47 * 48 * XE_VALIDATION_OPT_OUT is for simplification of kunit tests where 49 * exhaustive eviction isn't necessary. 50 */ 51 #define __XE_VAL_UNIMPLEMENTED -EINVAL 52 #define XE_VALIDATION_UNIMPLEMENTED (xe_validation_lockdep(), \ 53 (struct drm_exec *)ERR_PTR(__XE_VAL_UNIMPLEMENTED)) 54 55 #define __XE_VAL_UNSUPPORTED -EOPNOTSUPP 56 #define XE_VALIDATION_UNSUPPORTED ((struct drm_exec *)ERR_PTR(__XE_VAL_UNSUPPORTED)) 57 58 #define __XE_VAL_OPT_OUT -ENOMEM 59 #define XE_VALIDATION_OPT_OUT (xe_validation_lockdep(), \ 60 (struct drm_exec *)ERR_PTR(__XE_VAL_OPT_OUT)) 61 #ifdef CONFIG_DRM_XE_DEBUG 62 void xe_validation_assert_exec(const struct xe_device *xe, const struct drm_exec *exec, 63 const struct drm_gem_object *obj); 64 #else 65 #define xe_validation_assert_exec(_xe, _exec, _obj) \ 66 do { \ 67 (void)_xe; (void)_exec; (void)_obj; \ 68 } while (0) 69 #endif 70 71 /** 72 * struct xe_validation_device - The domain for exhaustive eviction 73 * @lock: The lock used to exclude other processes from allocating graphics memory 74 * 75 * The struct xe_validation_device represents the domain for which we want to use 76 * exhaustive eviction. The @lock is typically grabbed in read mode for allocations 77 * but when graphics memory allocation fails, it is retried with the write mode held. 78 */ 79 struct xe_validation_device { 80 struct rw_semaphore lock; 81 }; 82 83 /** 84 * struct xe_val_flags - Flags for xe_validation_ctx_init(). 85 * @exclusive: Start the validation transaction by locking out all other validators. 86 * @no_block: Don't block on initialization. 87 * @interruptible: Block interruptible if blocking. Implies initializing the drm_exec 88 * context with the DRM_EXEC_INTERRUPTIBLE_WAIT flag. 89 * @exec_ignore_duplicates: Initialize the drm_exec context with the 90 * DRM_EXEC_IGNORE_DUPLICATES flag. 91 */ 92 struct xe_val_flags { 93 u32 exclusive :1; 94 u32 no_block :1; 95 u32 interruptible :1; 96 u32 exec_ignore_duplicates :1; 97 }; 98 99 /** 100 * struct xe_validation_ctx - A struct drm_exec subclass with support for 101 * exhaustive eviction 102 * @exec: The drm_exec object base class. Note that we use a pointer instead of 103 * embedding to avoid diamond inheritance. 104 * @val: The exhaustive eviction domain. 105 * @val_flags: Copy of the struct xe_val_flags passed to xe_validation_ctx_init. 106 * @lock_held: Whether The domain lock is currently held. 107 * @lock_held_exclusive: Whether the domain lock is held in exclusive mode. 108 * @request_exclusive: Whether to lock exclusively (write mode) the next time 109 * the domain lock is locked. 110 * @exec_flags: The drm_exec flags used for drm_exec (re-)initialization. 111 * @nr: The drm_exec nr parameter used for drm_exec (re-)initializaiton. 112 */ 113 struct xe_validation_ctx { 114 struct drm_exec *exec; 115 struct xe_validation_device *val; 116 struct xe_val_flags val_flags; 117 bool lock_held; 118 bool lock_held_exclusive; 119 bool request_exclusive; 120 u32 exec_flags; 121 unsigned int nr; 122 }; 123 124 int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_device *val, 125 struct drm_exec *exec, const struct xe_val_flags flags); 126 127 int xe_validation_exec_lock(struct xe_validation_ctx *ctx, struct drm_gpuvm_exec *vm_exec, 128 struct xe_validation_device *val); 129 130 void xe_validation_ctx_fini(struct xe_validation_ctx *ctx); 131 132 bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret); 133 134 /** 135 * xe_validation_retry_on_oom() - Retry on oom in an xe_validaton transaction 136 * @_ctx: Pointer to the xe_validation_ctx 137 * @_ret: The current error value possibly holding -ENOMEM 138 * 139 * Use this in way similar to drm_exec_retry_on_contention(). 140 * If @_ret contains -ENOMEM the tranaction is restarted once in a way that 141 * blocks other transactions and allows exhastive eviction. If the transaction 142 * was already restarted once, Just return the -ENOMEM. May also set 143 * _ret to -EINTR if not retrying and waits are interruptible. 144 * May only be used within a drm_exec_until_all_locked() loop. 145 */ 146 #define xe_validation_retry_on_oom(_ctx, _ret) \ 147 do { \ 148 if (xe_validation_should_retry(_ctx, _ret)) \ 149 goto *__drm_exec_retry_ptr; \ 150 } while (0) 151 152 /** 153 * xe_validation_device_init - Initialize a struct xe_validation_device 154 * @val: The xe_validation_device to init. 155 */ 156 static inline void 157 xe_validation_device_init(struct xe_validation_device *val) 158 { 159 init_rwsem(&val->lock); 160 } 161 162 /* 163 * Make guard() and scoped_guard() work with xe_validation_ctx 164 * so that we can exit transactions without caring about the 165 * cleanup. 166 */ 167 DEFINE_CLASS(xe_validation, struct xe_validation_ctx *, 168 if (_T) xe_validation_ctx_fini(_T);, 169 ({_ret = xe_validation_ctx_init(_ctx, _val, _exec, _flags); 170 _ret ? NULL : _ctx; }), 171 struct xe_validation_ctx *_ctx, struct xe_validation_device *_val, 172 struct drm_exec *_exec, const struct xe_val_flags _flags, int _ret); 173 static inline void *class_xe_validation_lock_ptr(class_xe_validation_t *_T) 174 {return *_T; } 175 #define class_xe_validation_is_conditional true 176 177 /** 178 * xe_validation_guard() - An auto-cleanup xe_validation_ctx transaction 179 * @_ctx: The xe_validation_ctx. 180 * @_val: The xe_validation_device. 181 * @_exec: The struct drm_exec object 182 * @_flags: Flags for the xe_validation_ctx initialization. 183 * @_ret: Return in / out parameter. May be set by this macro. Typicall 0 when called. 184 * 185 * This macro is will initiate a drm_exec transaction with additional support for 186 * exhaustive eviction. 187 */ 188 #define xe_validation_guard(_ctx, _val, _exec, _flags, _ret) \ 189 scoped_guard(xe_validation, _ctx, _val, _exec, _flags, _ret) \ 190 drm_exec_until_all_locked(_exec) 191 192 #endif 193