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