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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
/* SPDX-License-Identifier: GPL-2.0 or MIT */
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
/* Copyright 2023 Collabora ltd. */
/* Copyright 2025 ARM Limited. All rights reserved. */
#ifndef __PANTHOR_GEM_H__
#define __PANTHOR_GEM_H__
#include <drm/drm_gem.h>
#include <drm/drm_mm.h>
#include <linux/iosys-map.h>
#include <linux/rwsem.h>
struct panthor_vm;
#define PANTHOR_BO_LABEL_MAXLEN 4096
enum panthor_debugfs_gem_state_flags {
PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT = 0,
PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT = 1,
PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT = 2,
/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED: GEM BO is PRIME imported. */
PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT),
/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED: GEM BO is PRIME exported. */
PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT),
/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED: GEM BO is evicted to swap. */
PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT),
};
enum panthor_debugfs_gem_usage_flags {
PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT = 0,
PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT = 1,
/** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL: BO is for kernel use only. */
PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL = BIT(PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT),
/** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED: BO is mapped on the FW VM. */
PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED = BIT(PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT),
};
/**
* struct panthor_gem_debugfs - GEM object's DebugFS list information
*/
struct panthor_gem_debugfs {
/**
* @node: Node used to insert the object in the device-wide list of
* GEM objects, to display information about it through a DebugFS file.
*/
struct list_head node;
/** @creator: Information about the UM process which created the GEM. */
struct {
/** @creator.process_name: Group leader name in owning thread's process */
char process_name[TASK_COMM_LEN];
/** @creator.tgid: PID of the thread's group leader within its process */
pid_t tgid;
} creator;
/** @flags: Combination of panthor_debugfs_gem_usage_flags flags */
u32 flags;
};
/**
* struct panthor_gem_backing - GEM memory backing related data
*/
struct panthor_gem_backing {
/** @pages: Pages requested with drm_gem_get_pages() */
struct page **pages;
/** @pin_count: Number of active pin requests on this GEM */
refcount_t pin_count;
};
/**
* struct panthor_gem_cpu_map - GEM CPU mapping related data
*/
struct panthor_gem_cpu_map {
/** @vaddr: Address returned by vmap() */
void *vaddr;
/** @vaddr_use_count: Number of active vmap() requests on this GEM */
refcount_t vaddr_use_count;
/** @mmap_count: Number of active mmap() requests on this GEM */
refcount_t mmap_count;
};
/**
* struct panthor_gem_dev_map - GEM device mapping related data
*/
struct panthor_gem_dev_map {
/** @sgt: Device mapped sg_table for this GEM */
struct sg_table *sgt;
};
/**
* enum panthor_gem_reclaim_state - Reclaim state of a GEM object
*
* This is defined in descending reclaimability order and some part
* of the code depends on that.
*/
enum panthor_gem_reclaim_state {
/**
* @PANTHOR_GEM_UNUSED: GEM is currently unused
*
* This can happen when the GEM was previously vmap-ed, mmap-ed,
* and/or GPU mapped and got unmapped. Because pages are lazily
* returned to the shmem layer, we want to keep a list of such
* BOs, because they should be fairly easy to reclaim (no need
* to wait for GPU to be done, and no need to tear down user
* mappings either).
*/
PANTHOR_GEM_UNUSED,
/**
* @PANTHOR_GEM_MMAPPED: GEM is currently mmap-ed
*
* When a GEM has pages allocated and the mmap_count is > 0, the
* GEM is placed in the mmapped list. This comes right after
* unused because we can relatively easily tear down user mappings.
*/
PANTHOR_GEM_MMAPPED,
/**
* @PANTHOR_GEM_GPU_MAPPED_SINGLE_VM: GEM is GPU mapped to only one VM
*
* When a GEM is mapped to a single VM, reclaim requests have more
* chances to succeed, because we only need to synchronize against
* a single GPU context. This is more annoying than reclaiming
* mmap-ed pages still, because we have to wait for in-flight jobs
* to land, and we might not be able to acquire all necessary locks
* at reclaim time either.
*/
PANTHOR_GEM_GPU_MAPPED_SINGLE_VM,
/**
* @PANTHOR_GEM_GPU_MAPPED_MULTI_VM: GEM is GPU mapped to multiple VMs
*
* Like PANTHOR_GEM_GPU_MAPPED_SINGLE_VM, but the synchronization across
* VMs makes such BOs harder to reclaim.
*/
PANTHOR_GEM_GPU_MAPPED_MULTI_VM,
/**
* @PANTHOR_GEM_UNRECLAIMABLE: GEM can't be reclaimed
*
* Happens when the GEM memory is pinned. It's also the state all GEM
* objects start in, because no memory is allocated until explicitly
* requested by a CPU or GPU map, meaning there's nothing to reclaim
* until such an allocation happens.
*/
PANTHOR_GEM_UNRECLAIMABLE,
};
/**
* struct panthor_gem_object - Driver specific GEM object.
*/
struct panthor_gem_object {
/** @base: Inherit from drm_gem_object. */
struct drm_gem_object base;
/** @backing: Memory backing state */
struct panthor_gem_backing backing;
/** @cmap: CPU mapping state */
struct panthor_gem_cpu_map cmap;
/** @dmap: Device mapping state */
struct panthor_gem_dev_map dmap;
/** @reclaim_state: Cached reclaim state */
enum panthor_gem_reclaim_state reclaim_state;
/**
* @reclaimed_count: How many times object has been evicted to swap.
* The count saturates at %INT_MAX and will never wrap around to 0.
*/
atomic_t reclaimed_count;
/**
* @exclusive_vm_root_gem: Root GEM of the exclusive VM this GEM object
* is attached to.
*
* If @exclusive_vm_root_gem != NULL, any attempt to bind the GEM to a
* different VM will fail.
*
* All FW memory objects have this field set to the root GEM of the MCU
* VM.
*/
struct drm_gem_object *exclusive_vm_root_gem;
/** @flags: Combination of drm_panthor_bo_flags flags. */
u32 flags;
/**
* @label: BO tagging fields. The label can be assigned within the
* driver itself or through a specific IOCTL.
*/
struct {
/**
* @label.str: Pointer to NULL-terminated string,
*/
const char *str;
/** @lock.str: Protects access to the @label.str field. */
struct mutex lock;
} label;
#ifdef CONFIG_DEBUG_FS
struct panthor_gem_debugfs debugfs;
#endif
};
/**
* struct panthor_kernel_bo - Kernel buffer object.
*
* These objects are only manipulated by the kernel driver and not
* directly exposed to the userspace. The GPU address of a kernel
* BO might be passed to userspace though.
*/
struct panthor_kernel_bo {
/**
* @obj: The GEM object backing this kernel buffer object.
*/
struct drm_gem_object *obj;
/**
* @vm: VM this private buffer is attached to.
*/
struct panthor_vm *vm;
/**
* @va_node: VA space allocated to this GEM.
*/
struct drm_mm_node va_node;
/**
* @kmap: Kernel CPU mapping of @gem.
*/
void *kmap;
};
#define to_panthor_bo(obj) container_of_const(obj, struct panthor_gem_object, base)
void panthor_gem_init(struct panthor_device *ptdev);
struct drm_gem_object *
panthor_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach,
struct sg_table *sgt);
int
panthor_gem_create_with_handle(struct drm_file *file,
struct drm_device *ddev,
struct panthor_vm *exclusive_vm,
u64 *size, u32 flags, uint32_t *handle);
struct sg_table *
panthor_gem_get_dev_sgt(struct panthor_gem_object *bo);
int panthor_gem_pin(struct panthor_gem_object *bo);
void panthor_gem_unpin(struct panthor_gem_object *bo);
int panthor_gem_swapin_locked(struct panthor_gem_object *bo);
void panthor_gem_update_reclaim_state_locked(struct panthor_gem_object *bo,
enum panthor_gem_reclaim_state *old_state);
int panthor_gem_shrinker_init(struct panthor_device *ptdev);
void panthor_gem_shrinker_unplug(struct panthor_device *ptdev);
void panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label);
void panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label);
int panthor_gem_sync(struct drm_gem_object *obj,
u32 type, u64 offset, u64 size);
struct drm_gem_object *
panthor_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf);
static inline u64
panthor_kernel_bo_gpuva(struct panthor_kernel_bo *bo)
{
return bo->va_node.start;
}
static inline size_t
panthor_kernel_bo_size(struct panthor_kernel_bo *bo)
{
return bo->obj->size;
}
static inline int
panthor_kernel_bo_vmap(struct panthor_kernel_bo *bo)
{
struct iosys_map map;
int ret;
if (bo->kmap)
return 0;
ret = drm_gem_vmap(bo->obj, &map);
if (ret)
return ret;
bo->kmap = map.vaddr;
return 0;
}
static inline void
panthor_kernel_bo_vunmap(struct panthor_kernel_bo *bo)
{
if (bo->kmap) {
struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->kmap);
drm_gem_vunmap(bo->obj, &map);
bo->kmap = NULL;
}
}
struct panthor_kernel_bo *
panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm,
size_t size, u32 bo_flags, u32 vm_map_flags,
u64 gpu_va, const char *name);
void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo);
struct panthor_gem_object *panthor_dummy_bo_create(struct panthor_device *ptdev);
#ifdef CONFIG_DEBUG_FS
void panthor_gem_debugfs_init(struct drm_minor *minor);
#endif
#endif /* __PANTHOR_GEM_H__ */
|